From 76cccc4a2f855791d5596c008f08feef745d876c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Sat, 11 Mar 2023 14:11:34 -0400 Subject: [PATCH 01/14] Update repo. --- .../bacnetip/readwrite/BACnetVendorId.java | 4 +++ .../s7/readwrite/S7VarPayloadDataItem.java | 36 ++++++++++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java index ebf2bba99d4..37ca4becec1 100644 --- a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java +++ b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java @@ -1609,16 +1609,19 @@ public enum BACnetVendorId { KOMFORTIQ_INC((int) 1397, (int) 1397, (String) "Komfort IQ, Inc."), COOL_TERA_LIMITED((int) 1398, (int) 1398, (String) "CoolTera Limited"), HADRON_SOLUTIONS_SRLS((int) 1399, (int) 1399, (String) "Hadron Solutions S.r.l.s"), + BITPOOL((int) 1401, (int) 1401, (String) "Bitpool"), SONICULLC((int) 1402, (int) 1402, (String) "Sonicu, LLC"), RISHABH_INSTRUMENTS_LIMITED((int) 1403, (int) 1403, (String) "Rishabh Instruments Limited"), THING_WAREHOUSELLC((int) 1404, (int) 1404, (String) "Thing Warehouse LLC"), INNOFRIENDS_GMBH((int) 1405, (int) 1405, (String) "Innofriends GmbH"), METRONICAKP_SPJ((int) 1406, (int) 1406, (String) "Metronic AKP Sp. J."), + TECHKNAVE((int) 1407, (int) 1407, (String) "Techknave"), ELSNER_ELEKTRONIK((int) 1408, (int) 1408, (String) "Elsner Elektronik"), LEFOO_INDUSTRIAL_HANGZHOU_CO_LTD( (int) 1409, (int) 1409, (String) "LEFOO Industrial (Hangzhou) Co., Ltd."), + CALIBRATION_TECHNOLOGIES_INC((int) 1410, (int) 1410, (String) "Calibration Technologies, Inc."), ALLORADO((int) 1411, (int) 1411, (String) "Allorado"), VERKADA((int) 1412, (int) 1412, (String) "Verkada"), @@ -1628,6 +1631,7 @@ public enum BACnetVendorId { OLYMPIA_ELECTRONICS((int) 1416, (int) 1416, (String) "Olympia Electronics"), NORMAL_SOFTWARE_INC((int) 1417, (int) 1417, (String) "Normal Software, Inc."), ST_ENGINEERING_SOLUTIONJSC((int) 1418, (int) 1418, (String) "ST Engineering Solution JSC"), + UNKNOWN_VENDOR((int) 0xFFFF, (int) 0xFFFF, (String) "Unknown"); private static final Map map; diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java index 4483814eac5..05ed37389e5 100644 --- a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java @@ -41,13 +41,18 @@ public class S7VarPayloadDataItem implements Message { protected final DataTransportErrorCode returnCode; protected final DataTransportSize transportSize; protected final byte[] data; + protected final Boolean hasNext; public S7VarPayloadDataItem( - DataTransportErrorCode returnCode, DataTransportSize transportSize, byte[] data) { + DataTransportErrorCode returnCode, + DataTransportSize transportSize, + byte[] data, + Boolean hasNext) { super(); this.returnCode = returnCode; this.transportSize = transportSize; this.data = data; + this.hasNext = hasNext; } public DataTransportErrorCode getReturnCode() { @@ -62,6 +67,10 @@ public byte[] getData() { return data; } + public Boolean getHasNext() { + return hasNext; + } + public void serialize(WriteBuffer writeBuffer) throws SerializationException { PositionAware positionAware = writeBuffer; boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); @@ -101,10 +110,13 @@ public void serialize(WriteBuffer writeBuffer) throws SerializationException { // Array Field (data) writeByteArrayField("data", data, writeByteArray(writeBuffer, 8)); + // Optional Field (hasNext) (Can be skipped, if the value is null) + writeOptionalField("hasNext", hasNext, writeBoolean(writeBuffer)); + // Padding Field (padding) writePaddingField( "padding", - (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0)), + (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0)), (short) 0x00, writeUnsignedShort(writeBuffer, 8)); @@ -136,8 +148,17 @@ public int getLengthInBits() { lengthInBits += 8 * data.length; } + // Optional Field (hasNext) + if (hasNext != null) { + lengthInBits += 1; + } + // Padding Field (padding) +<<<<<<< HEAD int _timesPadding = (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0)); +======= + int _timesPadding = (int) (((PADCOUNT(data, hasNext)) % (2))); +>>>>>>> fe65e60f40 (Test for S7VarPayloadItem.) while (_timesPadding-- > 0) { lengthInBits += 8; } @@ -180,13 +201,19 @@ public static S7VarPayloadDataItem staticParse(ReadBuffer readBuffer) throws Par Math.toIntExact( ((transportSize.getSizeInBits()) ? CEIL((dataLength) / (8.0)) : dataLength))); +<<<<<<< HEAD readPaddingField( readUnsignedShort(readBuffer, 8), (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0))); +======= + Boolean hasNext = readOptionalField("hasNext", readBoolean(readBuffer), (dataLength) < (-(1))); + + readPaddingField(readUnsignedShort(readBuffer, 8), (int) (((PADCOUNT(data, hasNext)) % (2)))); +>>>>>>> fe65e60f40 (Test for S7VarPayloadItem.) readBuffer.closeContext("S7VarPayloadDataItem"); // Create the instance S7VarPayloadDataItem _s7VarPayloadDataItem; - _s7VarPayloadDataItem = new S7VarPayloadDataItem(returnCode, transportSize, data); + _s7VarPayloadDataItem = new S7VarPayloadDataItem(returnCode, transportSize, data, hasNext); return _s7VarPayloadDataItem; } @@ -202,12 +229,13 @@ public boolean equals(Object o) { return (getReturnCode() == that.getReturnCode()) && (getTransportSize() == that.getTransportSize()) && (getData() == that.getData()) + && (getHasNext() == that.getHasNext()) && true; } @Override public int hashCode() { - return Objects.hash(getReturnCode(), getTransportSize(), getData()); + return Objects.hash(getReturnCode(), getTransportSize(), getData(), getHasNext()); } @Override From 39a90301793451900f56405c5098bfbbb32e0e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Thu, 16 Feb 2023 11:01:22 -0400 Subject: [PATCH 02/14] Update local repo. --- .../apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java index 05ed37389e5..2ef8f4bb003 100644 --- a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java @@ -116,7 +116,7 @@ public void serialize(WriteBuffer writeBuffer) throws SerializationException { // Padding Field (padding) writePaddingField( "padding", - (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0)), + (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0)), (short) 0x00, writeUnsignedShort(writeBuffer, 8)); From 56c1b5a113ea79269f858c6bd61b9e871e70d591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Sat, 4 Feb 2023 12:15:13 -0400 Subject: [PATCH 03/14] New feature _lastitem. --- .../org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java index 2ef8f4bb003..5cd7c9ebe58 100644 --- a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java @@ -119,7 +119,6 @@ public void serialize(WriteBuffer writeBuffer) throws SerializationException { (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0)), (short) 0x00, writeUnsignedShort(writeBuffer, 8)); - writeBuffer.popContext("S7VarPayloadDataItem"); } From c02fec13730046c17743011318988071425fc0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Thu, 16 Feb 2023 11:01:22 -0400 Subject: [PATCH 04/14] Update local repo. --- .../org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java | 1 + 1 file changed, 1 insertion(+) diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java index 5cd7c9ebe58..2ef8f4bb003 100644 --- a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java @@ -119,6 +119,7 @@ public void serialize(WriteBuffer writeBuffer) throws SerializationException { (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0)), (short) 0x00, writeUnsignedShort(writeBuffer, 8)); + writeBuffer.popContext("S7VarPayloadDataItem"); } From 0595c0d38fbe1055e1409efcda73bca9e59ed0c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Wed, 22 Feb 2023 20:02:32 -0400 Subject: [PATCH 05/14] Update repo. --- .../bacnetip/readwrite/BACnetVendorId.java | 1 - .../s7/readwrite/S7VarPayloadDataItem.java | 34 ++----------------- 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java index 37ca4becec1..b3f73c66439 100644 --- a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java +++ b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java @@ -1609,7 +1609,6 @@ public enum BACnetVendorId { KOMFORTIQ_INC((int) 1397, (int) 1397, (String) "Komfort IQ, Inc."), COOL_TERA_LIMITED((int) 1398, (int) 1398, (String) "CoolTera Limited"), HADRON_SOLUTIONS_SRLS((int) 1399, (int) 1399, (String) "Hadron Solutions S.r.l.s"), - BITPOOL((int) 1401, (int) 1401, (String) "Bitpool"), SONICULLC((int) 1402, (int) 1402, (String) "Sonicu, LLC"), RISHABH_INSTRUMENTS_LIMITED((int) 1403, (int) 1403, (String) "Rishabh Instruments Limited"), diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java index 2ef8f4bb003..4483814eac5 100644 --- a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java @@ -41,18 +41,13 @@ public class S7VarPayloadDataItem implements Message { protected final DataTransportErrorCode returnCode; protected final DataTransportSize transportSize; protected final byte[] data; - protected final Boolean hasNext; public S7VarPayloadDataItem( - DataTransportErrorCode returnCode, - DataTransportSize transportSize, - byte[] data, - Boolean hasNext) { + DataTransportErrorCode returnCode, DataTransportSize transportSize, byte[] data) { super(); this.returnCode = returnCode; this.transportSize = transportSize; this.data = data; - this.hasNext = hasNext; } public DataTransportErrorCode getReturnCode() { @@ -67,10 +62,6 @@ public byte[] getData() { return data; } - public Boolean getHasNext() { - return hasNext; - } - public void serialize(WriteBuffer writeBuffer) throws SerializationException { PositionAware positionAware = writeBuffer; boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); @@ -110,9 +101,6 @@ public void serialize(WriteBuffer writeBuffer) throws SerializationException { // Array Field (data) writeByteArrayField("data", data, writeByteArray(writeBuffer, 8)); - // Optional Field (hasNext) (Can be skipped, if the value is null) - writeOptionalField("hasNext", hasNext, writeBoolean(writeBuffer)); - // Padding Field (padding) writePaddingField( "padding", @@ -148,17 +136,8 @@ public int getLengthInBits() { lengthInBits += 8 * data.length; } - // Optional Field (hasNext) - if (hasNext != null) { - lengthInBits += 1; - } - // Padding Field (padding) -<<<<<<< HEAD int _timesPadding = (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0)); -======= - int _timesPadding = (int) (((PADCOUNT(data, hasNext)) % (2))); ->>>>>>> fe65e60f40 (Test for S7VarPayloadItem.) while (_timesPadding-- > 0) { lengthInBits += 8; } @@ -201,19 +180,13 @@ public static S7VarPayloadDataItem staticParse(ReadBuffer readBuffer) throws Par Math.toIntExact( ((transportSize.getSizeInBits()) ? CEIL((dataLength) / (8.0)) : dataLength))); -<<<<<<< HEAD readPaddingField( readUnsignedShort(readBuffer, 8), (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0))); -======= - Boolean hasNext = readOptionalField("hasNext", readBoolean(readBuffer), (dataLength) < (-(1))); - - readPaddingField(readUnsignedShort(readBuffer, 8), (int) (((PADCOUNT(data, hasNext)) % (2)))); ->>>>>>> fe65e60f40 (Test for S7VarPayloadItem.) readBuffer.closeContext("S7VarPayloadDataItem"); // Create the instance S7VarPayloadDataItem _s7VarPayloadDataItem; - _s7VarPayloadDataItem = new S7VarPayloadDataItem(returnCode, transportSize, data, hasNext); + _s7VarPayloadDataItem = new S7VarPayloadDataItem(returnCode, transportSize, data); return _s7VarPayloadDataItem; } @@ -229,13 +202,12 @@ public boolean equals(Object o) { return (getReturnCode() == that.getReturnCode()) && (getTransportSize() == that.getTransportSize()) && (getData() == that.getData()) - && (getHasNext() == that.getHasNext()) && true; } @Override public int hashCode() { - return Objects.hash(getReturnCode(), getTransportSize(), getData(), getHasNext()); + return Objects.hash(getReturnCode(), getTransportSize(), getData()); } @Override From 35869e8b4e7a22a733c2ebd8b21f0a2ed85b5e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Thu, 27 Apr 2023 17:19:47 -0400 Subject: [PATCH 06/14] Fix BACnetVendorId. --- .../apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java index b3f73c66439..ebf2bba99d4 100644 --- a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java +++ b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java @@ -1615,12 +1615,10 @@ public enum BACnetVendorId { THING_WAREHOUSELLC((int) 1404, (int) 1404, (String) "Thing Warehouse LLC"), INNOFRIENDS_GMBH((int) 1405, (int) 1405, (String) "Innofriends GmbH"), METRONICAKP_SPJ((int) 1406, (int) 1406, (String) "Metronic AKP Sp. J."), - TECHKNAVE((int) 1407, (int) 1407, (String) "Techknave"), ELSNER_ELEKTRONIK((int) 1408, (int) 1408, (String) "Elsner Elektronik"), LEFOO_INDUSTRIAL_HANGZHOU_CO_LTD( (int) 1409, (int) 1409, (String) "LEFOO Industrial (Hangzhou) Co., Ltd."), - CALIBRATION_TECHNOLOGIES_INC((int) 1410, (int) 1410, (String) "Calibration Technologies, Inc."), ALLORADO((int) 1411, (int) 1411, (String) "Allorado"), VERKADA((int) 1412, (int) 1412, (String) "Verkada"), @@ -1630,7 +1628,6 @@ public enum BACnetVendorId { OLYMPIA_ELECTRONICS((int) 1416, (int) 1416, (String) "Olympia Electronics"), NORMAL_SOFTWARE_INC((int) 1417, (int) 1417, (String) "Normal Software, Inc."), ST_ENGINEERING_SOLUTIONJSC((int) 1418, (int) 1418, (String) "ST Engineering Solution JSC"), - UNKNOWN_VENDOR((int) 0xFFFF, (int) 0xFFFF, (String) "Unknown"); private static final Map map; From 126152a7d507588dda358e8d4ecd7010f8f0b975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Thu, 16 Feb 2023 11:08:53 -0400 Subject: [PATCH 07/14] Update repo. --- .../bacnetip/readwrite/BACnetVendorId.java | 3 ++ .../s7/readwrite/S7VarPayloadDataItem.java | 36 ++++++++++++++++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java index ebf2bba99d4..df150c902f1 100644 --- a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java +++ b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java @@ -1609,12 +1609,14 @@ public enum BACnetVendorId { KOMFORTIQ_INC((int) 1397, (int) 1397, (String) "Komfort IQ, Inc."), COOL_TERA_LIMITED((int) 1398, (int) 1398, (String) "CoolTera Limited"), HADRON_SOLUTIONS_SRLS((int) 1399, (int) 1399, (String) "Hadron Solutions S.r.l.s"), + BITPOOL((int) 1401, (int) 1401, (String) "Bitpool"), SONICULLC((int) 1402, (int) 1402, (String) "Sonicu, LLC"), RISHABH_INSTRUMENTS_LIMITED((int) 1403, (int) 1403, (String) "Rishabh Instruments Limited"), THING_WAREHOUSELLC((int) 1404, (int) 1404, (String) "Thing Warehouse LLC"), INNOFRIENDS_GMBH((int) 1405, (int) 1405, (String) "Innofriends GmbH"), METRONICAKP_SPJ((int) 1406, (int) 1406, (String) "Metronic AKP Sp. J."), + TECHKNAVE((int) 1407, (int) 1407, (String) "Techknave"), ELSNER_ELEKTRONIK((int) 1408, (int) 1408, (String) "Elsner Elektronik"), LEFOO_INDUSTRIAL_HANGZHOU_CO_LTD( @@ -1628,6 +1630,7 @@ public enum BACnetVendorId { OLYMPIA_ELECTRONICS((int) 1416, (int) 1416, (String) "Olympia Electronics"), NORMAL_SOFTWARE_INC((int) 1417, (int) 1417, (String) "Normal Software, Inc."), ST_ENGINEERING_SOLUTIONJSC((int) 1418, (int) 1418, (String) "ST Engineering Solution JSC"), + UNKNOWN_VENDOR((int) 0xFFFF, (int) 0xFFFF, (String) "Unknown"); private static final Map map; diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java index 4483814eac5..05ed37389e5 100644 --- a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java @@ -41,13 +41,18 @@ public class S7VarPayloadDataItem implements Message { protected final DataTransportErrorCode returnCode; protected final DataTransportSize transportSize; protected final byte[] data; + protected final Boolean hasNext; public S7VarPayloadDataItem( - DataTransportErrorCode returnCode, DataTransportSize transportSize, byte[] data) { + DataTransportErrorCode returnCode, + DataTransportSize transportSize, + byte[] data, + Boolean hasNext) { super(); this.returnCode = returnCode; this.transportSize = transportSize; this.data = data; + this.hasNext = hasNext; } public DataTransportErrorCode getReturnCode() { @@ -62,6 +67,10 @@ public byte[] getData() { return data; } + public Boolean getHasNext() { + return hasNext; + } + public void serialize(WriteBuffer writeBuffer) throws SerializationException { PositionAware positionAware = writeBuffer; boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); @@ -101,10 +110,13 @@ public void serialize(WriteBuffer writeBuffer) throws SerializationException { // Array Field (data) writeByteArrayField("data", data, writeByteArray(writeBuffer, 8)); + // Optional Field (hasNext) (Can be skipped, if the value is null) + writeOptionalField("hasNext", hasNext, writeBoolean(writeBuffer)); + // Padding Field (padding) writePaddingField( "padding", - (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0)), + (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0)), (short) 0x00, writeUnsignedShort(writeBuffer, 8)); @@ -136,8 +148,17 @@ public int getLengthInBits() { lengthInBits += 8 * data.length; } + // Optional Field (hasNext) + if (hasNext != null) { + lengthInBits += 1; + } + // Padding Field (padding) +<<<<<<< HEAD int _timesPadding = (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0)); +======= + int _timesPadding = (int) (((PADCOUNT(data, hasNext)) % (2))); +>>>>>>> fe65e60f40 (Test for S7VarPayloadItem.) while (_timesPadding-- > 0) { lengthInBits += 8; } @@ -180,13 +201,19 @@ public static S7VarPayloadDataItem staticParse(ReadBuffer readBuffer) throws Par Math.toIntExact( ((transportSize.getSizeInBits()) ? CEIL((dataLength) / (8.0)) : dataLength))); +<<<<<<< HEAD readPaddingField( readUnsignedShort(readBuffer, 8), (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0))); +======= + Boolean hasNext = readOptionalField("hasNext", readBoolean(readBuffer), (dataLength) < (-(1))); + + readPaddingField(readUnsignedShort(readBuffer, 8), (int) (((PADCOUNT(data, hasNext)) % (2)))); +>>>>>>> fe65e60f40 (Test for S7VarPayloadItem.) readBuffer.closeContext("S7VarPayloadDataItem"); // Create the instance S7VarPayloadDataItem _s7VarPayloadDataItem; - _s7VarPayloadDataItem = new S7VarPayloadDataItem(returnCode, transportSize, data); + _s7VarPayloadDataItem = new S7VarPayloadDataItem(returnCode, transportSize, data, hasNext); return _s7VarPayloadDataItem; } @@ -202,12 +229,13 @@ public boolean equals(Object o) { return (getReturnCode() == that.getReturnCode()) && (getTransportSize() == that.getTransportSize()) && (getData() == that.getData()) + && (getHasNext() == that.getHasNext()) && true; } @Override public int hashCode() { - return Objects.hash(getReturnCode(), getTransportSize(), getData()); + return Objects.hash(getReturnCode(), getTransportSize(), getData(), getHasNext()); } @Override From 033f533b76190fa2698652495c8046798093eaf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Wed, 22 Feb 2023 20:02:32 -0400 Subject: [PATCH 08/14] Update repo. --- .../bacnetip/readwrite/BACnetVendorId.java | 1 - .../s7/readwrite/S7VarPayloadDataItem.java | 34 ++----------------- 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java index df150c902f1..43a5539556e 100644 --- a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java +++ b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java @@ -1609,7 +1609,6 @@ public enum BACnetVendorId { KOMFORTIQ_INC((int) 1397, (int) 1397, (String) "Komfort IQ, Inc."), COOL_TERA_LIMITED((int) 1398, (int) 1398, (String) "CoolTera Limited"), HADRON_SOLUTIONS_SRLS((int) 1399, (int) 1399, (String) "Hadron Solutions S.r.l.s"), - BITPOOL((int) 1401, (int) 1401, (String) "Bitpool"), SONICULLC((int) 1402, (int) 1402, (String) "Sonicu, LLC"), RISHABH_INSTRUMENTS_LIMITED((int) 1403, (int) 1403, (String) "Rishabh Instruments Limited"), diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java index 05ed37389e5..0d6c861cb25 100644 --- a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7VarPayloadDataItem.java @@ -41,18 +41,13 @@ public class S7VarPayloadDataItem implements Message { protected final DataTransportErrorCode returnCode; protected final DataTransportSize transportSize; protected final byte[] data; - protected final Boolean hasNext; public S7VarPayloadDataItem( - DataTransportErrorCode returnCode, - DataTransportSize transportSize, - byte[] data, - Boolean hasNext) { + DataTransportErrorCode returnCode, DataTransportSize transportSize, byte[] data) { super(); this.returnCode = returnCode; this.transportSize = transportSize; this.data = data; - this.hasNext = hasNext; } public DataTransportErrorCode getReturnCode() { @@ -67,10 +62,6 @@ public byte[] getData() { return data; } - public Boolean getHasNext() { - return hasNext; - } - public void serialize(WriteBuffer writeBuffer) throws SerializationException { PositionAware positionAware = writeBuffer; boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); @@ -110,9 +101,6 @@ public void serialize(WriteBuffer writeBuffer) throws SerializationException { // Array Field (data) writeByteArrayField("data", data, writeByteArray(writeBuffer, 8)); - // Optional Field (hasNext) (Can be skipped, if the value is null) - writeOptionalField("hasNext", hasNext, writeBoolean(writeBuffer)); - // Padding Field (padding) writePaddingField( "padding", @@ -148,17 +136,8 @@ public int getLengthInBits() { lengthInBits += 8 * data.length; } - // Optional Field (hasNext) - if (hasNext != null) { - lengthInBits += 1; - } - // Padding Field (padding) -<<<<<<< HEAD int _timesPadding = (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0)); -======= - int _timesPadding = (int) (((PADCOUNT(data, hasNext)) % (2))); ->>>>>>> fe65e60f40 (Test for S7VarPayloadItem.) while (_timesPadding-- > 0) { lengthInBits += 8; } @@ -201,19 +180,13 @@ public static S7VarPayloadDataItem staticParse(ReadBuffer readBuffer) throws Par Math.toIntExact( ((transportSize.getSizeInBits()) ? CEIL((dataLength) / (8.0)) : dataLength))); -<<<<<<< HEAD readPaddingField( readUnsignedShort(readBuffer, 8), (int) ((((!(_lastItem))) ? ((COUNT(data)) % (2)) : 0))); -======= - Boolean hasNext = readOptionalField("hasNext", readBoolean(readBuffer), (dataLength) < (-(1))); - - readPaddingField(readUnsignedShort(readBuffer, 8), (int) (((PADCOUNT(data, hasNext)) % (2)))); ->>>>>>> fe65e60f40 (Test for S7VarPayloadItem.) readBuffer.closeContext("S7VarPayloadDataItem"); // Create the instance S7VarPayloadDataItem _s7VarPayloadDataItem; - _s7VarPayloadDataItem = new S7VarPayloadDataItem(returnCode, transportSize, data, hasNext); + _s7VarPayloadDataItem = new S7VarPayloadDataItem(returnCode, transportSize, data); return _s7VarPayloadDataItem; } @@ -229,13 +202,12 @@ public boolean equals(Object o) { return (getReturnCode() == that.getReturnCode()) && (getTransportSize() == that.getTransportSize()) && (getData() == that.getData()) - && (getHasNext() == that.getHasNext()) && true; } @Override public int hashCode() { - return Objects.hash(getReturnCode(), getTransportSize(), getData(), getHasNext()); + return Objects.hash(getReturnCode(), getTransportSize(), getData()); } @Override From 9510b94c26dabb6787ccfd6d52cf7d1ea4dc0a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Thu, 23 Feb 2023 21:11:20 -0400 Subject: [PATCH 09/14] Update repo. --- .../apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java index 43a5539556e..8f5d0a26fcd 100644 --- a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java +++ b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java @@ -1615,6 +1615,7 @@ public enum BACnetVendorId { THING_WAREHOUSELLC((int) 1404, (int) 1404, (String) "Thing Warehouse LLC"), INNOFRIENDS_GMBH((int) 1405, (int) 1405, (String) "Innofriends GmbH"), METRONICAKP_SPJ((int) 1406, (int) 1406, (String) "Metronic AKP Sp. J."), +<<<<<<< HEAD TECHKNAVE((int) 1407, (int) 1407, (String) "Techknave"), ELSNER_ELEKTRONIK((int) 1408, (int) 1408, (String) "Elsner Elektronik"), @@ -1629,6 +1630,8 @@ public enum BACnetVendorId { OLYMPIA_ELECTRONICS((int) 1416, (int) 1416, (String) "Olympia Electronics"), NORMAL_SOFTWARE_INC((int) 1417, (int) 1417, (String) "Normal Software, Inc."), ST_ENGINEERING_SOLUTIONJSC((int) 1418, (int) 1418, (String) "ST Engineering Solution JSC"), + TECHKNAVE((int) 1407, (int) 1407, (String) "Techknave"), + ELSNER_ELEKTRONIK((int) 1408, (int) 1408, (String) "Elsner Elektronik"), UNKNOWN_VENDOR((int) 0xFFFF, (int) 0xFFFF, (String) "Unknown"); private static final Map map; From 9ddf709c63a048eb13f3c0c1ee42e760432d82a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Tue, 28 Feb 2023 13:48:37 -0400 Subject: [PATCH 10/14] Apache Hop integration. --- .../apache-hop/plc4x-hop-actions/pom.xml | 146 ++ .../hop/actions/ActionSampleMetaData.java | 35 + .../hop/actions/Plc4xCheckConnections.java | 271 ++++ .../actions/Plc4xCheckConnectionsDialog.java | 371 +++++ .../messages/messages_en_US.properties | 49 + .../src/main/resources/plc4x_toddy.svg | 1306 +++++++++++++++++ .../plc4x-hop-assemblies-action/pom.xml | 82 ++ .../src/assembly/assembly.xml | 52 + .../src/main/resources/version.xml | 20 + .../plc4x-hop-assemblies-metadata/pom.xml | 82 ++ .../src/assembly/assembly.xml | 69 + .../src/main/resources/version.xml | 20 + .../plc4x-hop-assemblies-transform/pom.xml | 82 ++ .../src/assembly/assembly.xml | 52 + .../src/main/resources/version.xml | 20 + .../apache-hop/plc4x-hop-assemblies/pom.xml | 42 + .../apache-hop/plc4x-hop-metadata/pom.xml | 129 ++ .../plc4x/hop/metadata/Plc4xConnection.java | 73 + .../hop/metadata/Plc4xConnectionEditor.java | 148 ++ .../messages/messages_en_US.properties | 22 + .../src/main/resources/plc4x_toddy.svg | 1306 +++++++++++++++++ .../apache-hop/plc4x-hop-transformer/pom.xml | 143 ++ .../hop/transforms/plc4xevent/Plc4xEvent.java | 346 +++++ .../transforms/plc4xevent/Plc4xEventData.java | 50 + .../plc4xevent/Plc4xEventDialog.java | 663 +++++++++ .../transforms/plc4xevent/Plc4xEventMeta.java | 239 +++ .../hop/transforms/plc4xinput/Plc4xRead.java | 446 ++++++ .../transforms/plc4xinput/Plc4xReadData.java | 48 + .../plc4xinput/Plc4xReadDialog.java | 600 ++++++++ .../transforms/plc4xinput/Plc4xReadMeta.java | 308 ++++ .../transforms/plc4xoutput/Plc4xWrite.java | 478 ++++++ .../plc4xoutput/Plc4xWriteData.java | 49 + .../plc4xoutput/Plc4xWriteDialog.java | 674 +++++++++ .../plc4xoutput/Plc4xWriteMeta.java | 310 ++++ .../hop/transforms/plc4xsubs/Plc4xSubs.java | 446 ++++++ .../transforms/plc4xsubs/Plc4xSubsData.java | 49 + .../transforms/plc4xsubs/Plc4xSubsDialog.java | 601 ++++++++ .../transforms/plc4xsubs/Plc4xSubsMeta.java | 310 ++++ .../hop/transforms/util/Plc4xDataType.java | 115 ++ .../transforms/util/Plc4xGeneratorField.java | 275 ++++ .../hop/transforms/util/Plc4xPlcField.java | 148 ++ .../util/Plc4xWrapperConnection.java | 60 + .../messages/messages_en_US.properties | 69 + .../messages/messages_es_ES.properties | 69 + .../messages/messages_en_US.properties | 69 + .../messages/messages_es_ES.properties | 69 + .../messages/messages_en_US.properties | 69 + .../messages/messages_es_ES.properties | 69 + .../messages/messages_en_US.properties | 69 + .../messages/messages_es_ES.properties | 69 + .../src/main/resources/plc4x_action.svg | 1306 +++++++++++++++++ .../src/main/resources/plc4x_event.svg | 822 +++++++++++ .../src/main/resources/plc4x_read.svg | 813 ++++++++++ .../src/main/resources/plc4x_subs.svg | 743 ++++++++++ .../src/main/resources/plc4x_write.svg | 810 ++++++++++ .../plc4x-hop-utils/hop-plc4x-grafana/pom.xml | 138 ++ .../utils/transforms/grafana/GrafanaPost.java | 589 ++++++++ .../grafana/GrafanaPostArgumentField.java | 70 + .../transforms/grafana/GrafanaPostData.java | 66 + .../transforms/grafana/GrafanaPostDialog.java | 1098 ++++++++++++++ .../grafana/GrafanaPostLoookupField.java | 65 + .../transforms/grafana/GrafanaPostMeta.java | 425 ++++++ .../transforms/grafana/GrafanaPostQuery.java | 57 + .../grafana/GrafanaPostResultField.java | 90 ++ .../src/main/resources/grafana.svg | 103 ++ .../messages/messages_en_US.properties | 138 ++ .../apache-hop/plc4x-hop-utils/pom.xml | 33 + plc4j/integrations/apache-hop/pom.xml | 251 ++++ plc4j/integrations/pom.xml | 1 + .../protocols/ads/images/ads-statemachine.svg | 1 + .../asciidoc/images/plc4x-architecture.png | Bin 0 -> 24761 bytes 71 files changed, 18906 insertions(+) create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-actions/pom.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/ActionSampleMetaData.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckConnections.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckConnectionsDialog.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/resources/org/apache/plc4x/hop/actions/messages/messages_en_US.properties create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/resources/plc4x_toddy.svg create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-action/pom.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-action/src/assembly/assembly.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-action/src/main/resources/version.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/pom.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/src/assembly/assembly.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/src/main/resources/version.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/pom.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/src/assembly/assembly.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/src/main/resources/version.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-assemblies/pom.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-metadata/pom.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/java/org/apache/plc4x/hop/metadata/Plc4xConnection.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/java/org/apache/plc4x/hop/metadata/Plc4xConnectionEditor.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/resources/org/apache/plc4x/hop/metadata/messages/messages_en_US.properties create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/resources/plc4x_toddy.svg create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/pom.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEvent.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventData.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventDialog.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventMeta.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xRead.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadData.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadDialog.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadMeta.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWrite.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteData.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteDialog.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteMeta.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubs.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsData.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsDialog.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsMeta.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xDataType.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xGeneratorField.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcField.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xWrapperConnection.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xevent/messages/messages_en_US.properties create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xevent/messages/messages_es_ES.properties create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xinput/messages/messages_en_US.properties create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xinput/messages/messages_es_ES.properties create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xoutput/messages/messages_en_US.properties create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xoutput/messages/messages_es_ES.properties create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xsubs/messages/messages_en_US.properties create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xsubs/messages/messages_es_ES.properties create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_action.svg create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_event.svg create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_read.svg create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_subs.svg create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_write.svg create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/pom.xml create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPost.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostArgumentField.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostData.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostDialog.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostLoookupField.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostMeta.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostQuery.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostResultField.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/resources/grafana.svg create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/resources/org/apache/plc4x/hop/utils/transforms/grafana/messages/messages_en_US.properties create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-utils/pom.xml create mode 100644 plc4j/integrations/apache-hop/pom.xml create mode 100644 src/site/asciidoc/developers/protocols/ads/images/ads-statemachine.svg create mode 100644 src/site/asciidoc/images/plc4x-architecture.png diff --git a/plc4j/integrations/apache-hop/plc4x-hop-actions/pom.xml b/plc4j/integrations/apache-hop/plc4x-hop-actions/pom.xml new file mode 100644 index 00000000000..ee58270dbcc --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-actions/pom.xml @@ -0,0 +1,146 @@ + + + + 4.0.0 + + org.apache.plc4x + plc4j-apache-hop + 0.11.0-SNAPSHOT + + plc4x-hop-action + jar + PLC4J: Integrations: Apache Hop: Action + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + org.jboss.jandex + jandex-maven-plugin + 1.0.8 + + + make-index + + jandex + + + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + org.apache.plc4x:plc4j-api:jar:${project.version} + org.apache.plc4x:plc4j-spi:jar:${project.version} + org.apache.plc4x:plc4j-driver-s7:jar:${project.version} + org.apache.plc4x:plc4j-transport-tcp:jar:${project.version} + + + + + + + + + org.apache.hop + hop-core + ${hop.version} + + + * + * + + + + + org.apache.hop + hop-ui + ${hop.version} + + + org.apache.hop + hop-engine + + + + + org.eclipse.platform + org.eclipse.swt.gtk.linux.x86_64 + ${org.eclipse.platform.version} + + + org.apache.plc4x + plc4j-driver-s7 + ${project.version} + + + org.apache.plc4x + plc4j-api + ${project.version} + + + org.apache.plc4x + plc4j-spi + ${project.version} + + + org.apache.plc4x + plc4j-transport-tcp + ${project.version} + + + ${project.groupId} + plc4x-hop-metadata + ${project.version} + + + org.apache.hop + hop-engine + ${hop.version} + + + * + * + + + + + + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/ActionSampleMetaData.java b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/ActionSampleMetaData.java new file mode 100644 index 00000000000..ecaaf6efdf7 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/ActionSampleMetaData.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.plc4x.hop.actions; + +import org.apache.hop.metadata.api.HopMetadata; +import org.apache.hop.metadata.api.HopMetadataBase; +import org.apache.hop.metadata.api.IHopMetadata; + +/** + * + * @author cgarcia + */ +@HopMetadata( + key = "Xplc4xconnection", + name = "PLC4x Connection", + description = "A shared PLC4x connection to a PLC", + image = "plc4x_toddy.svg", + documentationUrl = "/metadata-types/neo4j/neo4j-connection.html") +public class ActionSampleMetaData extends HopMetadataBase implements IHopMetadata { + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckConnections.java b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckConnections.java new file mode 100644 index 00000000000..752890f7f23 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckConnections.java @@ -0,0 +1,271 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.actions; + +import org.apache.hop.core.ICheckResult; +import org.apache.hop.core.Result; +import org.apache.hop.core.annotations.Action; +import org.apache.hop.core.exception.HopXmlException; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.core.xml.XmlHandler; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.metadata.api.IHopMetadataProvider; +import org.apache.hop.workflow.WorkflowMeta; +import org.apache.hop.workflow.action.ActionBase; +import org.apache.hop.workflow.action.IAction; + + +import java.util.List; +import org.apache.hop.core.Const; +import org.apache.hop.core.exception.HopException; +import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.w3c.dom.Node; + + +@Action( + id = "CHECK_PLC4X_CONNECTIONS", + name = "i18n::Plc4xAction.Name", + description = "i18n::Plc4xAction.Description", + image = "plc4x_toddy.svg", + categoryDescription = "i18n:org.apache.hop.workflow:ActionCategory.Category.Conditions", + keywords = "i18n::Plc4xAction.keyword", + documentationUrl = "/workflow/actions/checkdbconnection.html") +public class Plc4xCheckConnections extends ActionBase implements Cloneable, IAction { + private static final Class PKG = Plc4xCheckConnections.class; // Needed by Translator + + + private Plc4xConnection[] connections; + + protected static final String[] unitTimeDesc = + new String[] { + BaseMessages.getString(PKG, "Plc4xCheckConnections.UnitTimeMilliSecond.Label"), + BaseMessages.getString(PKG, "Plc4xCheckConnections.UnitTimeSecond.Label"), + BaseMessages.getString(PKG, "Plc4xCheckConnections.UnitTimeMinute.Label"), + BaseMessages.getString(PKG, "Plc4xCheckConnections.UnitTimeHour.Label"), + }; + protected static final String[] unitTimeCode = + new String[] {"millisecond", "second", "minute", "hour"}; + + public static final int UNIT_TIME_MILLI_SECOND = 0; + public static final int UNIT_TIME_SECOND = 1; + public static final int UNIT_TIME_MINUTE = 2; + public static final int UNIT_TIME_HOUR = 3; + + private String[] waitfors; + private int[] waittimes; + + private long timeStart; + private long now; + + public Plc4xCheckConnections( String name) { + super(name, ""); + //connections = null; + waitfors = null; + waittimes = null; + } + + public Plc4xCheckConnections() { + this( ""); + } + + public Object clone() { + Plc4xCheckConnections c = (Plc4xCheckConnections) super.clone(); + return c; + } + + + public Plc4xConnection[] getConnections() { + return connections; + } + + public void setConnections(Plc4xConnection[] connections) { + this.connections = connections; + } + + public String[] getWaitfors() { + return waitfors; + } + + public void setWaitfors(String[] waitfors) { + this.waitfors = waitfors; + } + + public int[] getWaittimes() { + return waittimes; + } + + public void setWaittimes(int[] waittimes) { + this.waittimes = waittimes; + } + + public long getTimeStart() { + return timeStart; + } + + public long getNow() { + return now; + } + + private static String getWaitTimeCode(int i) { + if (i < 0 || i >= unitTimeCode.length) { + return unitTimeCode[0]; + } + return unitTimeCode[i]; + } + + public static String getWaitTimeDesc(int i) { + if (i < 0 || i >= unitTimeDesc.length) { + return unitTimeDesc[0]; + } + return unitTimeDesc[i]; + } + + public static int getWaitTimeByDesc(String tt) { + if (tt == null) { + return 0; + } + + for (int i = 0; i < unitTimeDesc.length; i++) { + if (unitTimeDesc[i].equalsIgnoreCase(tt)) { + return i; + } + } + + // If this fails, try to match using the code. + return getWaitTimeByCode(tt); + } + + private static int getWaitTimeByCode(String tt) { + if (tt == null) { + return 0; + } + + for (int i = 0; i < unitTimeCode.length; i++) { + if (unitTimeCode[i].equalsIgnoreCase(tt)) { + return i; + } + } + return 0; + } + + + + /** + * + * Save values to XML + * + * @return + */ + @Override + public String getXml() { + StringBuilder xml = new StringBuilder(120); + xml.append(super.getXml()); + xml.append(" ").append(Const.CR); + if (connections != null) { + for (int i = 0; i < connections.length; i++) { + xml.append(" ").append(Const.CR); + xml.append(" ") + .append( + XmlHandler.addTagValue( + "name", connections[i] == null ? null : connections[i].getName())); + xml.append(" ").append(XmlHandler.addTagValue("waitfor", waitfors[i])); + xml.append(" ") + .append(XmlHandler.addTagValue("waittime", getWaitTimeCode(waittimes[i]))); + xml.append(" ").append(Const.CR); + } + } + xml.append(" ").append(Const.CR); + + return xml.toString(); + } + + /** + * + * Read the XML and get the values needed for the acton + * + * @param entrynode + * @param metadataProvider + * @throws HopXmlException + */ + @Override + public void loadXml( Node entrynode, IHopMetadataProvider metadataProvider, IVariables variables ) throws HopXmlException { + try { + super.loadXml(entrynode); + Node fields = XmlHandler.getSubNode(entrynode, "connections"); + + // How many hosts? + int nrFields = XmlHandler.countNodes(fields, "connection"); + connections = new Plc4xConnection[nrFields]; + waitfors = new String[nrFields]; + waittimes = new int[nrFields]; + // Read them all... + for (int i = 0; i < nrFields; i++) { + Node fnode = XmlHandler.getSubNodeByNr(fields, "connection", i); + String dbname = XmlHandler.getTagValue(fnode, "name"); + + //connections[i] = Plc4xConnection.loadDatabase(metadataProvider, dbname); + if (dbname != null) { + connections[i] = metadataProvider.getSerializer(Plc4xConnection.class).load(dbname); + waitfors[i] = XmlHandler.getTagValue(fnode, "waitfor"); + waittimes[i] = getWaitTimeByCode(Const.NVL(XmlHandler.getTagValue(fnode, "waittime"), "")); + }; + } + } catch (HopXmlException xe) { + throw new HopXmlException( + BaseMessages.getString( + PKG, + "Plc4xCheckConnections.ERROR_0001_Cannot_Load_Job_Entry_From_Xml_Node", + xe.getMessage())); + } catch (HopException ex) { + throw new HopXmlException( + BaseMessages.getString( + PKG, + "Plc4xCheckConnections.ERROR_0001_Cannot_Load_Job_Entry_From_Xml_Node", + ex.getMessage())); + } + } + + /** + * Execute this action and return the result. In this case it means, just set the result boolean in the Result + * class. + * + * @param result The result of the previous execution + * @return The Result of the execution. + */ + @Override + public Result execute( Result result, int nr ) { + result.setResult(true); + System.out.println("NR: " + nr); + + return result; + } + + /** + * + * Add checks to report warnings + * + * @param remarks + * @param workflowMeta + * @param variables + * @param metadataProvider + */ + @Override + public void check( List remarks, WorkflowMeta workflowMeta, IVariables variables, + IHopMetadataProvider metadataProvider ) { + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckConnectionsDialog.java b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckConnectionsDialog.java new file mode 100644 index 00000000000..791d3b88611 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckConnectionsDialog.java @@ -0,0 +1,371 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.plc4x.hop.actions; + +import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.hop.core.Const; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.util.Utils; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.ui.core.dialog.BaseDialog; +import org.apache.hop.ui.core.gui.WindowProperty; +import org.apache.hop.ui.core.widget.ColumnInfo; +import org.apache.hop.ui.core.widget.TableView; +import org.apache.hop.ui.pipeline.transform.BaseTransformDialog; +import org.apache.hop.ui.workflow.action.ActionDialog; +import org.apache.hop.ui.workflow.dialog.WorkflowDialog; +import org.apache.hop.workflow.WorkflowMeta; +import org.apache.hop.workflow.action.IAction; +import org.apache.hop.workflow.action.IActionDialog; +import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.*; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.*; + +import org.apache.hop.metadata.api.IHopMetadata; +import org.apache.hop.ui.core.dialog.ErrorDialog; +import org.apache.hop.ui.core.metadata.MetadataManager; +import org.apache.hop.ui.core.widget.MetaSelectionLine; + + +public class Plc4xCheckConnectionsDialog extends ActionDialog implements IActionDialog { + private static final Class PKG = Plc4xCheckConnectionsDialog.class; // Needed by Translator + + private Shell shell; + + private Text wName; + + private Plc4xCheckConnections action; + + private boolean changed; + + private TableView wFields; + + private MetaSelectionLine wConnection; + + public Plc4xCheckConnectionsDialog(Shell parent, IAction action, WorkflowMeta workflowMeta, IVariables variables) { + super( parent, workflowMeta, variables ); + this.action = (Plc4xCheckConnections) action; + if ( this.action.getName() == null ) { + this.action.setName( BaseMessages.getString( PKG, "Plc4xCheckConnections.Label" ) ); + } + } + + @Override + public IAction open() { + Shell parent = getParent(); + + shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.MIN | SWT.MAX | SWT.RESIZE); + props.setLook(shell); + WorkflowDialog.setShellImage(shell, action); + + ModifyListener lsMod = (ModifyEvent e) -> action.setChanged(); + changed = action.hasChanged(); + + FormLayout formLayout = new FormLayout(); + formLayout.marginWidth = Const.FORM_MARGIN; + formLayout.marginHeight = Const.FORM_MARGIN; + + shell.setLayout(formLayout); + shell.setText(BaseMessages.getString(PKG, "Plc4xCheckonnections.Title")); + + int middle = props.getMiddlePct(); + int margin = Const.MARGIN; + + // Buttons at the bottom + // + Button wOk = new Button(shell, SWT.PUSH); + wOk.setText(BaseMessages.getString(PKG, "System.Button.OK")); + wOk.addListener(SWT.Selection, (Event e) -> ok()); + Button wCancel = new Button(shell, SWT.PUSH); + wCancel.setText(BaseMessages.getString(PKG, "System.Button.Cancel")); + wCancel.addListener(SWT.Selection, (Event e) -> cancel()); + BaseTransformDialog.positionBottomButtons(shell, new Button[] {wOk, wCancel}, margin, null); + + // Filename line + Label wlName = new Label(shell, SWT.RIGHT); + wlName.setText(BaseMessages.getString(PKG, "Plc4xCheckConnections.Name.Label")); + props.setLook(wlName); + FormData fdlName = new FormData(); + fdlName.left = new FormAttachment(0, 0); + fdlName.right = new FormAttachment(middle, -margin); + fdlName.top = new FormAttachment(0, margin); + wlName.setLayoutData(fdlName); + wName = new Text(shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wName); + wName.addModifyListener(lsMod); + FormData fdName = new FormData(); + fdName.left = new FormAttachment(middle, 0); + fdName.top = new FormAttachment(0, margin); + fdName.right = new FormAttachment(100, 0); + wName.setLayoutData(fdName); + + Label wlFields = new Label(shell, SWT.NONE); + wlFields.setText(BaseMessages.getString(PKG, "Plc4xCheckConnections.Fields.Label")); + props.setLook(wlFields); + FormData fdlFields = new FormData(); + fdlFields.left = new FormAttachment(0, 0); + // fdlFields.right= new FormAttachment(middle, -margin); + fdlFields.top = new FormAttachment(wName, 2 * margin); + wlFields.setLayoutData(fdlFields); + + + wConnection = + new MetaSelectionLine<>( + variables, + metadataProvider, + Plc4xConnection.class, + shell, + SWT.NONE, + BaseMessages.getString(PKG, "Plc4xCheckConnections.Connection.Label"), + BaseMessages.getString(PKG, "Plc4xCheckConnections.Connection.Tooltip")); + props.setLook(wConnection); + FormData fdConnection = new FormData(); + fdConnection.left = new FormAttachment(0, 0); + fdConnection.right = new FormAttachment(100, 0); + //fdConnection.top = new FormAttachment(wTransformName, margin); + wConnection.setLayoutData(fdConnection); + + try { + wConnection.fillItems(); + } catch (Exception e) { + new ErrorDialog(shell, "Error", "Error listing Cassandra connection metadata objects", e); + } + + + // Buttons to the right of the screen... + Button wbGetConnections = new Button(shell, SWT.PUSH | SWT.CENTER); + props.setLook(wbGetConnections); + wbGetConnections.setText( + BaseMessages.getString(PKG, "Plc4xCheckConnections.GetConnections")); + wbGetConnections.setToolTipText( + BaseMessages.getString(PKG, "Plc4xCheckConnections.GetConnections.Tooltip")); + FormData fdbGetConnections = new FormData(); + fdbGetConnections.right = new FormAttachment(100, -margin); + fdbGetConnections.top = new FormAttachment(wlFields, margin); + wbGetConnections.setLayoutData(fdbGetConnections); + + // Buttons to the right of the screen... + Button wbdSourceFileFolder = new Button(shell, SWT.PUSH | SWT.CENTER); + props.setLook(wbdSourceFileFolder); + wbdSourceFileFolder.setText( + BaseMessages.getString(PKG, "Plc4xCheckConnections.DeleteEntry")); + wbdSourceFileFolder.setToolTipText( + BaseMessages.getString(PKG, "Plc4xCheckConnections.DeleteSourceFileButton.Label")); + FormData fdbdSourceFileFolder = new FormData(); + fdbdSourceFileFolder.right = new FormAttachment(100, -margin); + fdbdSourceFileFolder.top = new FormAttachment(wbGetConnections, margin); + wbdSourceFileFolder.setLayoutData(fdbdSourceFileFolder); + + int rows = + action.getConnections() == null + ? 1 + : (action.getConnections().length == 0 ? 0 : action.getConnections().length); + + final int FieldsRows = rows; + + ColumnInfo[] colinf = + new ColumnInfo[] { + new ColumnInfo( + BaseMessages.getString(PKG, "Plc4xCheckConnections.Fields.Argument.Label"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + this.getWorkflowMeta().getDatabaseNames(), + false), + new ColumnInfo( + BaseMessages.getString(PKG, "Plc4xCheckConnections.Fields.WaitFor.Label"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "Plc4xCheckConnections.Fields.WaitForTime.Label"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + Plc4xCheckConnections.unitTimeDesc, + false), + }; + + colinf[0].setToolTip(BaseMessages.getString(PKG, "Plc4xCheckConnections.Fields.Column")); + colinf[1].setUsingVariables(true); + colinf[1].setToolTip(BaseMessages.getString(PKG, "Plc4xCheckConnections.WaitFor.ToolTip")); + + wFields = + new TableView( + variables, + shell, + SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI, + colinf, + FieldsRows, + lsMod, + props); + + FormData fdFields = new FormData(); + fdFields.left = new FormAttachment(0, 0); + fdFields.top = new FormAttachment(wlFields, margin); + fdFields.right = new FormAttachment(wbGetConnections, -margin); + fdFields.bottom = new FormAttachment(wOk, -2 * margin); + wFields.setLayoutData(fdFields); + + // Delete files from the list of files... + wbdSourceFileFolder.addListener( + SWT.Selection, + e -> { + int[] idx = wFields.getSelectionIndices(); + wFields.remove(idx); + wFields.removeEmptyRows(); + wFields.setRowNums(); + }); + + // get connections... + wbGetConnections.addListener(SWT.Selection, e -> getConnections()); + + getData(); + + BaseDialog.defaultShellHandling(shell, c -> ok(), c -> cancel()); + + return action; + } + + // public void addDatabases() { + // connections = workflowMeta.getDatabaseNames(); + // } + + public void getConnections() { + /* + this.workflowMeta.getMetadataProvider().getMetadataClasses().forEach( + (c) -> { + System.out.println("Name: " + c.getName()); + }); + IHopMetadataProvider hmdp = this.workflowMeta.getMetadataProvider(); + */ + Class metadataClass = null; + + java.util.List databases = new ArrayList<>(); //this.workflowMeta.getMetadataProvider(). + try { + metadataClass = metadataProvider.getMetadataClassForKey("plc4x-connection"); + MetadataManager manager = new MetadataManager<>(variables, metadataProvider, metadataClass, null); + manager.getNames().forEach((s)->{ + try { + databases.add((Plc4xConnection) manager.loadElement(s)); + } catch (HopException ex) { + Logger.getLogger(Plc4xCheckConnectionsDialog.class.getName()).log(Level.SEVERE, null, ex); + } + }); + + } catch (Exception ex) { + Logger.getLogger(Plc4xCheckConnectionsDialog.class.getName()).log(Level.SEVERE, null, ex); + } + + + wFields.removeAll(); + + for (Plc4xConnection ci : databases) { + if (ci != null) { + wFields.add(new String[] {ci.getName(), "0", Plc4xCheckConnections.unitTimeDesc[0]}); + } + } + wFields.removeEmptyRows(); + wFields.setRowNums(); + wFields.optWidth(true); + } + + public void dispose() { + WindowProperty winprop = new WindowProperty(shell); + props.setScreen(winprop); + shell.dispose(); + } + + /** Copy information from the meta-data input to the dialog fields. */ + public void getData() { + if (action.getName() != null) { + wName.setText(action.getName()); + } + + if (action.getConnections() != null) { + for (int i = 0; i < action.getConnections().length; i++) { + TableItem ti = wFields.table.getItem(i); + if (action.getConnections()[i] != null) { + ti.setText(1, action.getConnections()[i].getName()); + ti.setText(2, "" + Const.toInt(action.getWaitfors()[i], 0)); + ti.setText(3, Plc4xCheckConnections.getWaitTimeDesc(action.getWaittimes()[i])); + } + } + wFields.setRowNums(); + wFields.optWidth(true); + } + wName.selectAll(); + wName.setFocus(); + } + + private void cancel() { + action.setChanged(changed); + action = null; + dispose(); + } + + private void ok() { + if (Utils.isEmpty(wName.getText())) { + MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR); + mb.setText(BaseMessages.getString(PKG, "System.TransformActionNameMissing.Title")); + mb.setMessage(BaseMessages.getString(PKG, "System.ActionNameMissing.Msg")); + mb.open(); + return; + } + Class metadataClass = null; + action.setName(wName.getText()); + + int nrItems = wFields.nrNonEmpty(); + System.out.println("Numero de items: " + nrItems); + + Plc4xConnection[] connections = new Plc4xConnection[nrItems]; + String[] waitfors = new String[nrItems]; + int[] waittimes = new int[nrItems]; + + + try { + metadataClass = metadataProvider.getMetadataClassForKey("plc4x-connection"); + } catch (HopException ex) { + Logger.getLogger(Plc4xCheckConnectionsDialog.class.getName()).log(Level.SEVERE, null, ex); + } + MetadataManager manager = new MetadataManager<>(variables, metadataProvider, metadataClass, null); + + for (int i = 0; i < nrItems; i++) { + String arg = wFields.getNonEmpty(i).getText(1); + Plc4xConnection conn; + try { + conn = (Plc4xConnection) manager.loadElement(arg); + if (conn != null) { + connections[i] = conn; + waitfors[i] = "" + Const.toInt(wFields.getNonEmpty(i).getText(2), 0); + waittimes[i] = + Plc4xCheckConnections.getWaitTimeByDesc(wFields.getNonEmpty(i).getText(3)); + } + } catch (HopException ex) { + Logger.getLogger(Plc4xCheckConnectionsDialog.class.getName()).log(Level.SEVERE, null, ex); + } + + } + action.setConnections(connections); + action.setWaitfors(waitfors); + action.setWaittimes(waittimes); + + dispose(); + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/resources/org/apache/plc4x/hop/actions/messages/messages_en_US.properties b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/resources/org/apache/plc4x/hop/actions/messages/messages_en_US.properties new file mode 100644 index 00000000000..f13f6255eb2 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/resources/org/apache/plc4x/hop/actions/messages/messages_en_US.properties @@ -0,0 +1,49 @@ +# +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +Plc4xCheckConnections.Name=Check PLC connections +Plc4xCheckConnections.Description=Check if we can connect to one or several databases. +Plc4xCheckConnections.ConnectionOK=We can successfully connect to database [{0}] (connection [{1}]) +Plc4xCheckConnections.ERROR_0001_Cannot_Load_Job_Entry_From_Xml_Node=Unable to load action of type 'Check Db connection' from XML node. Exception : {0} +Plc4xCheckConnections.Exception=Cannot connect to database [{0}] (connection [{1}]). Exception : [{2}] +Plc4xCheckConnections.Log.Info.ConnectionsInSuccess=[{0}] connections were successfully checked. +Plc4xCheckConnections.Log.Info.ConnectionsInError=[{0}] connections were in error. +Plc4xCheckConnections.UnitTimeMilliSecond.Label=Milliseconds +Plc4xCheckConnections.UnitTimeSecond.Label=Seconds +Plc4xCheckConnections.UnitTimeMinute.Label=Minutes +Plc4xCheckConnections.UnitTimeHour.Label=Hours +Plc4xCheckConnections.Connected=Connected to database [{0}] (connection [{1}])... +Plc4xCheckConnections.Wait=We need to leave the connection open {0} {1} ... +Plc4xCheckConnections.WaitTimeIsElapsed.Label=Wait time is elapsed for plc [{0}] (connection [{1}]). The connection will be closed ... +Plc4xCheckConnections.Title=Check PLC connections +Plc4xCheckConnections.Name.Default=Check PLC connections +Plc4xCheckConnections.Name.Label=Action name +Plc4xCheckConnections.Fields.Argument.Label=Connection +Plc4xCheckConnections.Fields.Label=Connections +Plc4xCheckConnections.Fields.Column=Connections +Plc4xCheckConnections.Fields.WaitFor.Label=Wait +Plc4xCheckConnections.Fields.WaitForTime.Label=Units of time +Plc4xCheckConnections.WaitFor.ToolTip=After the connection was opened\nwait x (s, mn,..) +Plc4xCheckConnections.DeleteSourceFileButton.Label=Remove selected items from the list. +Plc4xCheckConnections.DeleteEntry=Delete +Plc4xCheckConnections.GetConnections=Get connections +Plc4xCheckConnections.GetConnections.Tooltip=Get available connections +Plc4xCheckConnections.keyword=check,plc,database,connection +Plc4xCheckConnections.Connection.Label +Plc4xCheckConnections.Connection.Tooltip \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/resources/plc4x_toddy.svg b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/resources/plc4x_toddy.svg new file mode 100644 index 00000000000..01694ecd5df --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/resources/plc4x_toddy.svg @@ -0,0 +1,1306 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-action/pom.xml b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-action/pom.xml new file mode 100644 index 00000000000..3f95f27e849 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-action/pom.xml @@ -0,0 +1,82 @@ + + + + 4.0.0 + + org.apache.plc4x + plc4x-hop-assemblies + 0.11.0-SNAPSHOT + + plc4x-hop-assemblies-action + pom + PLC4J: Integrations: Apache Hop: Assemblies: Action + + + + + org.apache.plc4x + plc4x-hop-action + ${project.version} + + + + + + + + maven-assembly-plugin + ${maven-assembly-plugin.version} + + + + + + + + assembly + + + ${basedir}/src/assembly/assembly.xml + + + + + + maven-assembly-plugin + + + assembly_package + compile + + single + + + ${basedir}/src/assembly + false + + + + + + + + + + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-action/src/assembly/assembly.xml b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-action/src/assembly/assembly.xml new file mode 100644 index 00000000000..84529d10bab --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-action/src/assembly/assembly.xml @@ -0,0 +1,52 @@ + + + + + plc4x-plugin-assemblies-action + + zip + + plugins/actions/plc4x + + + ${project.basedir}/src/main/resources/version.xml + . + true + + + + + lib + + **/* + + + + + + false + + org.apache.plc4x:plc4x-hop-action:jar + + + + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-action/src/main/resources/version.xml b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-action/src/main/resources/version.xml new file mode 100644 index 00000000000..2703899672c --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-action/src/main/resources/version.xml @@ -0,0 +1,20 @@ + + +${project.version} \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/pom.xml b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/pom.xml new file mode 100644 index 00000000000..290099015a3 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/pom.xml @@ -0,0 +1,82 @@ + + + + 4.0.0 + + org.apache.plc4x + plc4x-hop-assemblies + 0.11.0-SNAPSHOT + + + plc4x-hop-assemblies-metadata + pom + PLC4J: Integrations: Apache Hop: Assemblies: Metadata + + + + org.apache.plc4x + plc4x-hop-metadata + ${project.version} + + + + + + + + maven-assembly-plugin + ${maven-assembly-plugin.version} + + + + + + + + assembly + + + ${basedir}/src/assembly/assembly.xml + + + + + + maven-assembly-plugin + + + assembly_package + compile + + single + + + ${basedir}/src/assembly + false + + + + + + + + + + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/src/assembly/assembly.xml b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/src/assembly/assembly.xml new file mode 100644 index 00000000000..c79e5135186 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/src/assembly/assembly.xml @@ -0,0 +1,69 @@ + + + + + plc4x-plugin-assemblies-metadata + + zip + + plugins/metadata/plc4x + + + ${project.basedir}/src/main/resources/version.xml + . + true + + + + + lib + + **/* + + + + + + false + + org.apache.plc4x:plc4x-hop-metadata:jar + + + + + lib + false + true + runtime + + com.github.jinahya:bit-io:jar + ch.qos.logback:logback-core + io.netty:netty-buffer + io.netty:netty-codec:jar + io.netty:netty-common:jar + io.netty:netty-resolver:jar + io.netty:netty-transport + + + + + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/src/main/resources/version.xml b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/src/main/resources/version.xml new file mode 100644 index 00000000000..2703899672c --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/src/main/resources/version.xml @@ -0,0 +1,20 @@ + + +${project.version} \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/pom.xml b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/pom.xml new file mode 100644 index 00000000000..66253b85961 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/pom.xml @@ -0,0 +1,82 @@ + + + + 4.0.0 + + org.apache.plc4x + plc4x-hop-assemblies + 0.11.0-SNAPSHOT + + plc4x-hop-assemblies-transform + pom + PLC4J: Integrations: Apache Hop: Assemblies: Transform + + + + + org.apache.plc4x + plc4x-hop-transform + ${project.version} + + + + + + + + maven-assembly-plugin + ${maven-assembly-plugin.version} + + + + + + + + assembly + + + ${basedir}/src/assembly/assembly.xml + + + + + + maven-assembly-plugin + + + assembly_package + compile + + single + + + ${basedir}/src/assembly + false + + + + + + + + + + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/src/assembly/assembly.xml b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/src/assembly/assembly.xml new file mode 100644 index 00000000000..3321a4ce6fe --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/src/assembly/assembly.xml @@ -0,0 +1,52 @@ + + + + + plc4x-plugin-assemblies-transform + + zip + + plugins/transforms/plc4x + + + ${project.basedir}/src/main/resources/version.xml + . + true + + + + + lib + + **/* + + + + + + false + + org.apache.plc4x:plc4x-hop-transform:jar + + + + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/src/main/resources/version.xml b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/src/main/resources/version.xml new file mode 100644 index 00000000000..2703899672c --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/src/main/resources/version.xml @@ -0,0 +1,20 @@ + + +${project.version} \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/pom.xml b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/pom.xml new file mode 100644 index 00000000000..ccc6d04b8e7 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/pom.xml @@ -0,0 +1,42 @@ + + + + 4.0.0 + + + org.apache.plc4x + plc4j-apache-hop + 0.11.0-SNAPSHOT + + + plc4x-hop-assemblies + pom + PLC4J: Integrations: Apache Hop: Assemblies + + + ${project.build.directory}/assembly + + + + plc4x-hop-assemblies-metadata + plc4x-hop-assemblies-action + plc4x-hop-assemblies-transform + + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-metadata/pom.xml b/plc4j/integrations/apache-hop/plc4x-hop-metadata/pom.xml new file mode 100644 index 00000000000..22eccd03ab7 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-metadata/pom.xml @@ -0,0 +1,129 @@ + + + + 4.0.0 + + org.apache.plc4x + plc4j-apache-hop + 0.11.0-SNAPSHOT + + plc4x-hop-metadata + jar + + PLC4J: Integrations: Apache Hop: Metadata + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + org.jboss.jandex + jandex-maven-plugin + 1.0.8 + + + make-index + + jandex + + + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + org.apache.plc4x:plc4j-spi:jar:${project.version} + org.apache.plc4x:plc4j-driver-s7:jar:${project.version} + org.apache.plc4x:plc4j-transport-tcp:jar:${project.version} + org.apache.hop:hop-engine:jar:${hop.version} + javax.annotation:javax.annotation-api:jar:1.2 + + + + + + + + + org.apache.hop + hop-ui + ${hop.version} + + + org.apache.hop + hop-engine + ${hop.version} + + + * + * + + + + + org.eclipse.platform + org.eclipse.swt.gtk.linux.x86_64 + 3.114.0 + + + org.apache.plc4x + plc4j-driver-s7 + ${project.version} + + + org.apache.plc4x + plc4j-api + ${project.version} + + + org.apache.plc4x + plc4j-spi + ${project.version} + + + org.apache.plc4x + plc4j-transport-tcp + ${project.version} + + + org.apache.hop + hop-core + ${hop.version} + + + * + * + + + + + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/java/org/apache/plc4x/hop/metadata/Plc4xConnection.java b/plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/java/org/apache/plc4x/hop/metadata/Plc4xConnection.java new file mode 100644 index 00000000000..3a2b711c53c --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/java/org/apache/plc4x/hop/metadata/Plc4xConnection.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.plc4x.hop.metadata; + +import org.apache.hop.core.gui.plugin.GuiElementType; +import org.apache.hop.core.gui.plugin.GuiPlugin; +import org.apache.hop.core.gui.plugin.GuiWidgetElement; +import org.apache.hop.metadata.api.HopMetadata; +import org.apache.hop.metadata.api.HopMetadataBase; +import org.apache.hop.metadata.api.HopMetadataProperty; +import org.apache.hop.metadata.api.IHopMetadata; + +@GuiPlugin +@HopMetadata( + key = "plc4x-connection", + name = "Plc4x Connection", + description = "Describes a connection to a PLC", + image = "plc4x_toddy.svg", + documentationUrl = "/metadata-types/plc4x/plc4x-connection.html") +public class Plc4xConnection extends HopMetadataBase implements IHopMetadata { + + public static final String WIDGET_ID_URL = "10000-url"; + + @HopMetadataProperty + @GuiWidgetElement( + id = WIDGET_ID_URL, + type = GuiElementType.TEXT, + parentId = Plc4xConnectionEditor.PARENT_WIDGET_ID, + label = "URL", + toolTip = "Specify the hostname of your cassandra server") + private String url; + + + public Plc4xConnection() {} + + public Plc4xConnection(Plc4xConnection p) { + super(p.name); + this.url = p.url; + } + + + /** + * Gets url + * + * @return value of hostname + */ + public String getUrl() { + return url; + } + + /** @param hostname The hostname to set */ + public void setUrl(String url) { + this.url = url; + } + + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/java/org/apache/plc4x/hop/metadata/Plc4xConnectionEditor.java b/plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/java/org/apache/plc4x/hop/metadata/Plc4xConnectionEditor.java new file mode 100644 index 00000000000..1118a5ff741 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/java/org/apache/plc4x/hop/metadata/Plc4xConnectionEditor.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.plc4x.hop.metadata; + +import org.apache.hop.core.Const; +import org.apache.hop.ui.core.PropsUi; +import org.apache.hop.ui.core.dialog.ErrorDialog; +import org.apache.hop.ui.core.gui.GuiCompositeWidgets; +import org.apache.hop.ui.core.gui.GuiCompositeWidgetsAdapter; +import org.apache.hop.ui.core.metadata.IMetadataEditor; +import org.apache.hop.ui.core.metadata.MetadataEditor; +import org.apache.hop.ui.core.metadata.MetadataManager; +import org.apache.hop.ui.hopgui.HopGui; +import org.apache.plc4x.java.DefaultPlcDriverManager; +import org.apache.plc4x.java.api.PlcDriverManager; +import org.apache.plc4x.java.api.PlcConnection; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.widgets.*; + + +public class Plc4xConnectionEditor extends MetadataEditor + implements IMetadataEditor{ + + private static final Class PKG = Plc4xConnectionEditor.class; // For Translator + + public static final String PARENT_WIDGET_ID = "Plc4xConnectionEditor.Widgets.ParentId"; + + private Composite parent; + private Text wName; + private GuiCompositeWidgets widgets; + + public Plc4xConnectionEditor(HopGui hopGui, MetadataManager manager, Plc4xConnection metadata) { + super(hopGui, manager, metadata); + } + + + @Override + public void createControl(Composite parent) { + this.parent = parent; + PropsUi props = PropsUi.getInstance(); + int margin = props.getMargin(); + int middle = props.getMiddlePct(); + // Name... + // + // What's the name + Label wlName = new Label(parent, SWT.RIGHT); + props.setLook(wlName); + wlName.setText("Plc4x url name"); + FormData fdlName = new FormData(); + fdlName.top = new FormAttachment(0, margin * 2); + fdlName.left = new FormAttachment(0, 0); + fdlName.right = new FormAttachment(middle, 0); + wlName.setLayoutData(fdlName); + wName = new Text(parent, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wName); + + FormData fdName = new FormData(); + fdName.top = new FormAttachment(wlName, 0, SWT.CENTER); + fdName.left = new FormAttachment(middle, margin); + fdName.right = new FormAttachment(100, 0); + wName.setLayoutData(fdName); + + // Rest of the widgets... + // + widgets = new GuiCompositeWidgets(manager.getVariables()); + widgets.createCompositeWidgets(getMetadata(), null, parent, PARENT_WIDGET_ID, wName); + + // Set content on the widgets... + // + setWidgetsContent(); + + // Add changed listeners + wName.addListener(SWT.Modify, e -> setChanged()); + widgets.setWidgetsListener( + new GuiCompositeWidgetsAdapter() { + @Override + public void widgetModified( + GuiCompositeWidgets compositeWidgets, Control changedWidget, String widgetId) { + setChanged(); + } + }); + } + + + @Override + public void setWidgetsContent() { + Plc4xConnection meta = getMetadata(); + wName.setText(Const.NVL(meta.getName(), "")); + widgets.setWidgetsContents(meta, parent, PARENT_WIDGET_ID); + } + + @Override + public void getWidgetsContent(Plc4xConnection meta) { + meta.setName(wName.getText()); + widgets.getWidgetsContents(meta, PARENT_WIDGET_ID); + } + + @Override + public Button[] createButtonsForButtonBar(Composite parent) { + PropsUi props = PropsUi.getInstance(); + + Button wbTest = new Button(parent, SWT.PUSH | SWT.CENTER); + props.setLook(wbTest); + wbTest.setText("Test"); + wbTest.addListener(SWT.Selection, e -> test()); + + return new Button[] {wbTest}; + } + + public void test() { + PlcConnection plcConnection; + try { + Plc4xConnection meta = getMetadata(); + plcConnection = new DefaultPlcDriverManager().getConnection(meta.getUrl()); + plcConnection.connect(); + Thread.sleep(100); + plcConnection.close(); + MessageBox box = new MessageBox(parent.getShell(), SWT.ICON_INFORMATION | SWT.OK); + box.setText("Success!"); + box.setMessage("It's possible to connect to Device with this metadata!"); + box.open(); + + } catch (Exception e) { + new ErrorDialog(parent.getShell(), "Error", "We couldn't connect using this information", e); + } + } + + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/resources/org/apache/plc4x/hop/metadata/messages/messages_en_US.properties b/plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/resources/org/apache/plc4x/hop/metadata/messages/messages_en_US.properties new file mode 100644 index 00000000000..6db5c3fea39 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/resources/org/apache/plc4x/hop/metadata/messages/messages_en_US.properties @@ -0,0 +1,22 @@ + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +Plc4x.Name=Sample Transform +Plc4x.Description=Sample Transform Description +Plc4x.Shell.Title=Sample Transform Title +Plc4x.TransformName.Label=Sample Name \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/resources/plc4x_toddy.svg b/plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/resources/plc4x_toddy.svg new file mode 100644 index 00000000000..01694ecd5df --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-metadata/src/main/resources/plc4x_toddy.svg @@ -0,0 +1,1306 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/pom.xml b/plc4j/integrations/apache-hop/plc4x-hop-transformer/pom.xml new file mode 100644 index 00000000000..e707e0d2069 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/pom.xml @@ -0,0 +1,143 @@ + + + + 4.0.0 + + org.apache.plc4x + plc4j-apache-hop + 0.11.0-SNAPSHOT + + + plc4x-hop-transform + jar + PLC4J: Integrations: Apache Hop: Transform + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + org.jboss.jandex + jandex-maven-plugin + 1.0.8 + + + make-index + + jandex + + + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + io.netty:netty-common:jar:4.1.89.Final + io.netty:netty-all:jar:4.1.89.Final + commons-lang:commons-lang:jar:2.6 + xml-apis:xml-apis:jar:1.4.01 + org.apache.plc4x:plc4j-spi:jar:${project.version} + com.fasterxml.jackson.core:jackson-annotations:jar:2.14.2 + + + + + + + + + + org.apache.hop + hop-core + ${hop.version} + compile + + + * + * + + + + + org.apache.hop + hop-engine + ${hop.version} + + + * + * + + + + + org.apache.hop + hop-ui + ${hop.version} + + + * + * + + + + + io.netty + netty-all + ${netty.version} + + + ${project.groupId} + plc4j-api + ${project.version} + + + ${project.groupId} + hop-plc4x-metadata + ${project.version} + + + org.eclipse.platform + org.eclipse.swt.gtk.linux.x86_64 + 3.114.0 + + + ${project.groupId} + plc4j-driver-s7 + ${project.version} + + + org.apache.commons + commons-lang3 + 3.12.0 + + + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEvent.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEvent.java new file mode 100644 index 00000000000..e87262ec01e --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEvent.java @@ -0,0 +1,346 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xevent; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; +import org.apache.hop.core.CheckResult; +import org.apache.hop.core.Const; +import org.apache.hop.core.ICheckResult; +import org.apache.hop.core.RowMetaAndData; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.exception.HopPluginException; +import org.apache.hop.core.logging.LogLevel; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.row.RowDataUtil; +import org.apache.hop.core.row.RowMeta; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.metadata.api.IHopMetadataProvider; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.transform.BaseTransform; +import org.apache.hop.pipeline.transform.ITransform; +import org.apache.hop.pipeline.transform.TransformMeta; +import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.apache.plc4x.hop.transforms.util.Plc4xWrapperConnection; +import org.apache.plc4x.java.DefaultPlcDriverManager; +import org.apache.plc4x.java.api.PlcConnection; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest; +import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse; +import org.apache.plc4x.java.api.model.PlcConsumerRegistration; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.s7.events.S7ModeEvent; +import org.apache.plc4x.java.s7.readwrite.ModeTransitionType; + +/** + * Transform That contains the basic skeleton needed to create your own plugin + * + */ +public class Plc4xEvent extends BaseTransform implements ITransform { + + public static String FIELD_MODE_EVENT = "MODE"; + public static String FIELD_USER_EVENT = "USR"; + public static String FIELD_SYS_EVENT = "SYS"; + public static String FIELD_ALARM_EVENT = "ALM"; + + + private static final Class PKG = Plc4xEvent.class; // Needed by Translator + + private Plc4xConnection connmeta = null; + private Plc4xWrapperConnection connwrapper = null; + private PlcReadRequest readRequest = null; + private PlcConsumerRegistration registerMode = null; + private PlcConsumerRegistration registerUser = null; + private PlcConsumerRegistration registerSys = null; + private PlcConsumerRegistration registerAlarm = null; + private PlcSubscriptionRequest subsbuild = null; + private PlcSubscriptionResponse subresponse = null; + + private static final ReentrantLock lock = new ReentrantLock(); + + private static final String dummy = "dummy"; + + public Plc4xEvent(TransformMeta transformMeta, Plc4xEventMeta meta, Plc4xEventData data, int copyNr, PipelineMeta pipelineMeta, + Pipeline pipeline ) { + super( transformMeta, meta, data, copyNr, pipelineMeta, pipeline ); + } + + /* + * Including Date and Time field for every row + * + * @param meta Meta data from user dialog + * @param remarks Error registers + * @param origin transform instance name + */ + public static final RowMetaAndData buildRow( + Plc4xEventMeta meta, List remarks, String origin) throws HopPluginException { + IRowMeta rowMeta = new RowMeta(); + Object[] rowData = RowDataUtil.allocateRowData(2); + int index = 0; + + return new RowMetaAndData(rowMeta, rowData); + } + + /* + * 1. Block the other instances by means of a lock. + * 2. Try to locate an existing connection. + * 3. If it doesn't exist, it tries to take control of the routine to + * create an instance of PlcConnection and his wrapper. + * 4. Register the connection wrapper for global access. + * 5. If the connection to the PLC is made, then it creates the query + * and executes it. + * + */ + @Override + public boolean processRow() throws HopException { + Object[] r = getRow(); // Get row from input rowset & set row busy! + setLogLevel(LogLevel.DEBUG); + + if ((!meta.isNeverEnding() && data.rowsWritten >= data.rowLimit) && !isStopped()) { + setOutputDone(); // signal end to receiver(s) + return false; + } + + lock.lock(); //(01) + try { + IHopMetadataProvider metaprovider = getMetadataProvider(); + connmeta = metaprovider.getSerializer(Plc4xConnection.class).load(meta.getConnection()); + if (connwrapper == null) { + connwrapper = (Plc4xWrapperConnection) getPipeline().getExtensionDataMap().get(meta.getConnection()); //(02) + if (connwrapper != null) connwrapper.retain(); + }; + + if (connmeta == null){ + logError( + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.Log.SetMetadata", + meta.getConnection())); + } + + if ((connmeta != null) && (connwrapper == null)){ + readRequest = null; + try{ + PlcConnection conn = new DefaultPlcDriverManager().getConnection(connmeta.getUrl()); //(03) + if (conn.isConnected()) { + connwrapper = new Plc4xWrapperConnection(conn); + getPipeline().getExtensionDataMap().put(meta.getConnection(), connwrapper); //(04) + } + } catch (Exception ex){ + setErrors(1L); + logError("Unable to create connection to PLC. " + ex.getMessage()); + } + } + } finally { + lock.unlock(); + } + + if ((connmeta != null) && (connwrapper != null)){ + if (connwrapper.getConnection().isConnected()){ + if (readRequest == null){ + final PlcSubscriptionRequest.Builder subscription = connwrapper.getConnection().subscriptionRequestBuilder(); //(05) + if (meta.isModeEvent()) subscription.addEventTagAddress(FIELD_MODE_EVENT, FIELD_MODE_EVENT); + if (meta.isUserEvent()) subscription.addEventTagAddress(FIELD_USER_EVENT, FIELD_USER_EVENT); + if (meta.isSysEvent()) subscription.addEventTagAddress(FIELD_SYS_EVENT, FIELD_SYS_EVENT); + if (meta.isAlarmEvent()) subscription.addEventTagAddress(FIELD_ALARM_EVENT, FIELD_ALARM_EVENT); + + subsbuild = subscription.build(); + + } + try { + subresponse = subsbuild.execute().get(); + + if (meta.isModeEvent() && subresponse.getResponseCode(FIELD_MODE_EVENT) == PlcResponseCode.OK) { + registerMode = + subresponse + .getSubscriptionHandle(FIELD_MODE_EVENT) + .register(msg -> { + System.out.println("******** S7ModeEvent ********"); + Map map = ((S7ModeEvent) msg).getMap(); + map.forEach((x, y) -> { + System.out.println(x + " : " + y); + }); + short currentmode = (short) + map.get(S7ModeEvent.Fields.CURRENT_MODE.name()); + System.out.println("CURRENT_MODE MSG: " + ModeTransitionType.enumForValue(currentmode).name()); + System.out.println("****************************"); + }); + } + + if (meta.isUserEvent() && subresponse.getResponseCode(FIELD_USER_EVENT) == PlcResponseCode.OK) { + registerUser = + subresponse + .getSubscriptionHandle(FIELD_USER_EVENT) + .register(msg -> { + System.out.println("******** S7ModeEvent ********"); + Map map = ((S7ModeEvent) msg).getMap(); + map.forEach((x, y) -> { + System.out.println(x + " : " + y); + }); + short currentmode = (short) + map.get(S7ModeEvent.Fields.CURRENT_MODE.name()); + System.out.println("CURRENT_MODE MSG: " + ModeTransitionType.enumForValue(currentmode).name()); + System.out.println("****************************"); + }); + } + + if (meta.isSysEvent() && subresponse.getResponseCode(FIELD_SYS_EVENT) == PlcResponseCode.OK) { + registerSys = + subresponse + .getSubscriptionHandle(FIELD_SYS_EVENT) + .register(msg -> { + System.out.println("******** S7ModeEvent ********"); + Map map = ((S7ModeEvent) msg).getMap(); + map.forEach((x, y) -> { + System.out.println(x + " : " + y); + }); + short currentmode = (short) + map.get(S7ModeEvent.Fields.CURRENT_MODE.name()); + System.out.println("CURRENT_MODE MSG: " + ModeTransitionType.enumForValue(currentmode).name()); + System.out.println("****************************"); + }); + } + + if (meta.isAlarmEvent() && subresponse.getResponseCode(FIELD_ALARM_EVENT) == PlcResponseCode.OK) { + registerAlarm = + subresponse + .getSubscriptionHandle(FIELD_ALARM_EVENT) + .register(msg -> { + System.out.println("******** S7ModeEvent ********"); + Map map = ((S7ModeEvent) msg).getMap(); + map.forEach((x, y) -> { + System.out.println(x + " : " + y); + }); + short currentmode = (short) + map.get(S7ModeEvent.Fields.CURRENT_MODE.name()); + System.out.println("CURRENT_MODE MSG: " + ModeTransitionType.enumForValue(currentmode).name()); + System.out.println("****************************"); + }); + } + + } catch (Exception ex) { + setErrors(1L); + logError("Unable read from PLC. " + ex.getMessage()); + } + + } else { + setErrors(1L); + logError("PLC is not connected."); + setOutputDone(); + return false; + } + + } else { + setErrors(1L); + logError("PLC connection don't exist."); + setOutputDone(); + return false; + } + + + r = data.outputRowMeta.cloneRow(data.outputRowData); + logBasic("Tamano de los datos: " + r.length); + data.prevDate = data.rowDate; + data.rowDate = new Date(); + + + putRow(data.outputRowMeta, r ); // return your data + data.rowsWritten++; + return true; + } + + + @Override + public boolean init() { + try { + if(super.init()){ + // Determine the number of rows to generate... + data.rowLimit = Const.toLong(resolve(meta.getRowLimit()), -1L); + + if (data.rowLimit < 0L) { // Unable to parse + logError(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Wrong.RowLimit.Number")); + return false; // fail + } + + // Create a row (constants) with all the values in it... + List remarks = new ArrayList<>(); // stores the errors... + RowMetaAndData outputRow = buildRow(meta, remarks, getTransformName()); + if (!remarks.isEmpty()) { + for (int i = 0; i < remarks.size(); i++) { + CheckResult cr = (CheckResult) remarks.get(i); + logError(cr.getText()); + } + return false; + } + + data.outputRowData = outputRow.getData(); + data.outputRowMeta = outputRow.getRowMeta(); + + return true; + } + return false; + } catch (Exception ex){ + setErrors(1L); + logError("Error initializing transform", ex); + return false; + } + } + + /* + * Here, must perform the cleaning of any resource, main of the connection to + * the associated PLC. + */ + @Override + public void cleanup() { + super.cleanup(); + logBasic("Cleanup. Release connection."); + if (connwrapper != null) + connwrapper.release(); + } + + + /* + * Here, must perform the cleaning of any resource. + * 1. Check if we have reference to wrapper. + * 2. Release de reference to object. + * 3. The lastone remove the global reference to connection wrapper. + * 4. Clear local references. + */ + @Override + public void dispose() { + super.dispose(); + if (connwrapper != null) { + logBasic("Dispose. Release connection: " + connwrapper.refCnt()); + connwrapper.release(); + if (!connwrapper.getConnection().isConnected()){ + getPipeline().getExtensionDataMap().remove(meta.getConnection()); + } + connwrapper = null; + readRequest = null; + + } + } + + + + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventData.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventData.java new file mode 100644 index 00000000000..ebadf2111be --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventData.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xevent; + +import org.apache.plc4x.hop.transforms.plc4xoutput.*; +import org.apache.plc4x.hop.transforms.plc4xinput.*; +import java.util.Date; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.pipeline.transform.BaseTransformData; +import org.apache.hop.pipeline.transform.ITransformData; + + +public class Plc4xEventData extends BaseTransformData implements ITransformData { + + //The Plc4xConnection metadata + public String connection; + + public IRowMeta outputRowMeta; + public Object[] outputRowData; + + public long rowLimit; + public long rowsWritten; + public Date rowDate; + public Date prevDate; + public long delay; + + + + /** + * Default constructor for SampleData. + */ + public Plc4xEventData() { + super(); + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventDialog.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventDialog.java new file mode 100644 index 00000000000..ea369b5cb74 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventDialog.java @@ -0,0 +1,663 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xevent; + +import org.apache.hop.core.Const; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.util.Utils; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.PipelinePreviewFactory; +import org.apache.hop.pipeline.transform.BaseTransformMeta; +import org.apache.hop.pipeline.transform.ITransformDialog; +import org.apache.hop.ui.core.ConstUi; +import org.apache.hop.ui.core.dialog.BaseDialog; +import org.apache.hop.ui.core.dialog.EnterNumberDialog; +import org.apache.hop.ui.core.dialog.EnterTextDialog; +import org.apache.hop.ui.core.dialog.ErrorDialog; +import org.apache.hop.ui.core.dialog.PreviewRowsDialog; +import org.apache.hop.ui.core.widget.MetaSelectionLine; +import org.apache.hop.ui.core.widget.TableView; +import org.apache.hop.ui.core.widget.TextVar; +import org.apache.hop.ui.pipeline.dialog.PipelinePreviewProgressDialog; +import org.apache.hop.ui.pipeline.transform.BaseTransformDialog; +import org.apache.hop.ui.util.SwtSvgImageUtil; +import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.*; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +public class Plc4xEventDialog extends BaseTransformDialog implements ITransformDialog { + private static final Class PKG = Plc4xEventDialog.class; // Needed by Translator + + private MetaSelectionLine wConnection; + + private Label wlLimit; + private TextVar wLimit; + + private Button wNeverEnding; + + private Button wModeEvent; + private Button wUserEvent; + private Button wSysEvent; + private Button wAlarmEvent; + + private Label wlMaxwait; + private TextVar wMaxwait; + + private Label wlInterval; + private TextVar wInterval; + + private Label wlRowTimeField; + private TextVar wRowTimeField; + + private Label wlLastTimeField; + private TextVar wLastTimeField; + + private TableView wFields; + + private final Plc4xEventMeta input; + + public Plc4xEventDialog(Shell parent, IVariables variables , Object in, PipelineMeta pipelineMeta, String sname ) { + super( parent, variables, (BaseTransformMeta) in, pipelineMeta, sname ); + input = (Plc4xEventMeta) in; + } + + @Override + public String open() { + Shell parent = getParent(); + + shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX | SWT.MIN); + props.setLook(shell); + setShellImage(shell, input); + + ModifyListener lsMod = e -> input.setChanged(); + changed = input.hasChanged(); + + FormLayout formLayout = new FormLayout(); + formLayout.marginWidth = Const.FORM_MARGIN; + formLayout.marginHeight = Const.FORM_MARGIN; + + shell.setLayout(formLayout); + shell.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.DialogTitle")); + + int middle = props.getMiddlePct(); + int margin = props.getMargin(); + + // Filename line + wlTransformName = new Label(shell, SWT.RIGHT); + wlTransformName.setText(BaseMessages.getString(PKG, "System.Label.TransformName")); + props.setLook(wlTransformName); + fdlTransformName = new FormData(); + fdlTransformName.left = new FormAttachment(0, 0); + fdlTransformName.right = new FormAttachment(middle, -margin); + fdlTransformName.top = new FormAttachment(0, margin); + wlTransformName.setLayoutData(fdlTransformName); + + wTransformName = new Text(shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + wTransformName.setText(transformName); + props.setLook(wTransformName); + wTransformName.addModifyListener(lsMod); + fdTransformName = new FormData(); + fdTransformName.left = new FormAttachment(middle, 0); + fdTransformName.top = new FormAttachment(0, margin); + fdTransformName.right = new FormAttachment(100, 0); + wTransformName.setLayoutData(fdTransformName); + + // Connection line + wConnection = + new MetaSelectionLine<>( + variables, + metadataProvider, + Plc4xConnection.class, + shell, + SWT.NONE, + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Connection.Label"), + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Connection.Tooltip")); + FormData fdConnection = new FormData(); + fdConnection.left = new FormAttachment(0, 0); + fdConnection.right = new FormAttachment(100, 0); + fdConnection.top = new FormAttachment(wTransformName, margin); + wConnection.setLayoutData(fdConnection); + props.setLook(wConnection); + try { + wConnection.fillItems(); + } catch (Exception e) { + new ErrorDialog(shell, "Error", "Error listing Cassandra connection metadata objects", e); + } + + Control lastControl = wConnection; + + wlLimit = new Label(shell, SWT.RIGHT); + wlLimit.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Limit.Label")); + props.setLook(wlLimit); + FormData fdlLimit = new FormData(); + fdlLimit.left = new FormAttachment(0, 0); + fdlLimit.right = new FormAttachment(middle, -margin); + fdlLimit.top = new FormAttachment(lastControl, margin); + wlLimit.setLayoutData(fdlLimit); + wLimit = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wLimit); + wLimit.addModifyListener(lsMod); + FormData fdLimit = new FormData(); + fdLimit.left = new FormAttachment(middle, 0); + fdLimit.top = new FormAttachment(lastControl, margin); + fdLimit.right = new FormAttachment(100, 0); + wLimit.setLayoutData(fdLimit); + lastControl = wLimit; + + /******************** + * Never Ending + ********************/ + Label wlNeverEnding = new Label(shell, SWT.RIGHT); + wlNeverEnding.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.NeverEnding.Label")); + props.setLook(wlNeverEnding); + FormData fdlNeverEnding = new FormData(); + fdlNeverEnding.left = new FormAttachment(0, 0); + fdlNeverEnding.right = new FormAttachment(middle, -margin); + fdlNeverEnding.top = new FormAttachment(lastControl, margin); + wlNeverEnding.setLayoutData(fdlNeverEnding); + wNeverEnding = new Button(shell, SWT.CHECK); + props.setLook(wNeverEnding); + wNeverEnding.addSelectionListener( + new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + setActive(); + input.setChanged(); + } + }); + + FormData fdNeverEnding = new FormData(); + fdNeverEnding.left = new FormAttachment(middle, 0); + fdNeverEnding.top = new FormAttachment(wlNeverEnding, 0, SWT.CENTER); + fdNeverEnding.right = new FormAttachment(100, 0); + wNeverEnding.setLayoutData(fdNeverEnding); + lastControl = wlNeverEnding; + + /******************** + * Mode Events + ********************/ + Label wlModeEvent = new Label(shell, SWT.RIGHT); + wlModeEvent.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.NeverEnding.Label")); + props.setLook(wlModeEvent); + FormData fdlModeEvent = new FormData(); + fdlModeEvent.left = new FormAttachment(0, 0); + fdlModeEvent.right = new FormAttachment(middle, -margin); + fdlModeEvent.top = new FormAttachment(lastControl, margin); + wlModeEvent.setLayoutData(fdlModeEvent); + wModeEvent = new Button(shell, SWT.CHECK); + props.setLook(wModeEvent); + wModeEvent.addSelectionListener( + new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + setActive(); + input.setChanged(); + } + }); + + FormData fdModeEvent = new FormData(); + fdModeEvent.left = new FormAttachment(middle, 0); + fdModeEvent.top = new FormAttachment(wlModeEvent, 0, SWT.CENTER); + fdModeEvent.right = new FormAttachment(100, 0); + wModeEvent.setLayoutData(fdModeEvent); + lastControl = wlModeEvent; + + /******************** + * User Events + ********************/ + Label wlUserEvent = new Label(shell, SWT.RIGHT); + wlUserEvent.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.NeverEnding.Label")); + props.setLook(wlUserEvent); + FormData fdlUserEvent = new FormData(); + fdlUserEvent.left = new FormAttachment(0, 0); + fdlUserEvent.right = new FormAttachment(middle, -margin); + fdlUserEvent.top = new FormAttachment(lastControl, margin); + wlUserEvent.setLayoutData(fdlUserEvent); + wUserEvent = new Button(shell, SWT.CHECK); + props.setLook(wUserEvent); + wUserEvent.addSelectionListener( + new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + setActive(); + input.setChanged(); + } + }); + + FormData fdUserEvent = new FormData(); + fdUserEvent.left = new FormAttachment(middle, 0); + fdUserEvent.top = new FormAttachment(wlUserEvent, 0, SWT.CENTER); + fdUserEvent.right = new FormAttachment(100, 0); + wUserEvent.setLayoutData(fdUserEvent); + lastControl = wlUserEvent; + + /******************** + * Sys Events + ********************/ + Label wlSysEvent = new Label(shell, SWT.RIGHT); + wlSysEvent.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.NeverEnding.Label")); + props.setLook(wlSysEvent); + FormData fdlSysEvent = new FormData(); + fdlSysEvent.left = new FormAttachment(0, 0); + fdlSysEvent.right = new FormAttachment(middle, -margin); + fdlSysEvent.top = new FormAttachment(lastControl, margin); + wlSysEvent.setLayoutData(fdlSysEvent); + wSysEvent = new Button(shell, SWT.CHECK); + props.setLook(wSysEvent); + wSysEvent.addSelectionListener( + new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + setActive(); + input.setChanged(); + } + }); + + FormData fdSysEvent = new FormData(); + fdSysEvent.left = new FormAttachment(middle, 0); + fdSysEvent.top = new FormAttachment(wlSysEvent, 0, SWT.CENTER); + fdSysEvent.right = new FormAttachment(100, 0); + wSysEvent.setLayoutData(fdSysEvent); + lastControl = wlSysEvent; + + /******************** + * Alarm Events + ********************/ + Label wlAlarmEvent = new Label(shell, SWT.RIGHT); + wlAlarmEvent.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.NeverEnding.Label")); + props.setLook(wlAlarmEvent); + FormData fdlAlarmEvent = new FormData(); + fdlAlarmEvent.left = new FormAttachment(0, 0); + fdlAlarmEvent.right = new FormAttachment(middle, -margin); + fdlAlarmEvent.top = new FormAttachment(lastControl, margin); + wlAlarmEvent.setLayoutData(fdlAlarmEvent); + wAlarmEvent = new Button(shell, SWT.CHECK); + props.setLook(wAlarmEvent); + wAlarmEvent.addSelectionListener( + new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + setActive(); + input.setChanged(); + } + }); + + FormData fdAlarmEvent = new FormData(); + fdAlarmEvent.left = new FormAttachment(middle, 0); + fdAlarmEvent.top = new FormAttachment(wlAlarmEvent, 0, SWT.CENTER); + fdAlarmEvent.right = new FormAttachment(100, 0); + wAlarmEvent.setLayoutData(fdAlarmEvent); + lastControl = wlAlarmEvent; + + + wOk = new Button(shell, SWT.PUSH); + wOk.setText(BaseMessages.getString(PKG, "System.Button.OK")); + wOk.addListener(SWT.Selection, e -> ok()); + + wCancel = new Button(shell, SWT.PUSH); + wCancel.setText(BaseMessages.getString(PKG, "System.Button.Cancel")); + wCancel.addListener(SWT.Selection, e -> cancel()); + + setButtonPositions(new Button[] {wOk, wCancel}, margin, null); + + /* + + wlMaxwait = new Label(shell, SWT.RIGHT); + wlMaxwait.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Maxwait.Label")); + props.setLook(wlMaxwait); + FormData fdlMaxwait = new FormData(); + fdlMaxwait.left = new FormAttachment(0, 0); + fdlMaxwait.right = new FormAttachment(middle, -margin); + fdlMaxwait.top = new FormAttachment(lastControl, margin); + wlMaxwait.setLayoutData(fdlMaxwait); + wMaxwait = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wMaxwait); + wMaxwait.addModifyListener(lsMod); + FormData fdMaxwait = new FormData(); + fdMaxwait.left = new FormAttachment(middle, 0); + fdMaxwait.top = new FormAttachment(lastControl, margin); + fdMaxwait.right = new FormAttachment(100, 0); + wMaxwait.setLayoutData(fdMaxwait); + lastControl = wMaxwait; + + wlInterval = new Label(shell, SWT.RIGHT); + wlInterval.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Interval.Label")); + props.setLook(wlInterval); + FormData fdlInterval = new FormData(); + fdlInterval.left = new FormAttachment(0, 0); + fdlInterval.right = new FormAttachment(middle, -margin); + fdlInterval.top = new FormAttachment(lastControl, margin); + wlInterval.setLayoutData(fdlInterval); + wInterval = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wInterval); + wInterval.addModifyListener(lsMod); + FormData fdInterval = new FormData(); + fdInterval.left = new FormAttachment(middle, 0); + fdInterval.top = new FormAttachment(lastControl, margin); + fdInterval.right = new FormAttachment(100, 0); + wInterval.setLayoutData(fdInterval); + lastControl = wInterval; + + + wlRowTimeField = new Label(shell, SWT.RIGHT); + wlRowTimeField.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.RowTimeField.Label")); + props.setLook(wlRowTimeField); + FormData fdlRowTimeField = new FormData(); + fdlRowTimeField.left = new FormAttachment(0, 0); + fdlRowTimeField.right = new FormAttachment(middle, -margin); + fdlRowTimeField.top = new FormAttachment(lastControl, margin); + wlRowTimeField.setLayoutData(fdlRowTimeField); + wRowTimeField = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wRowTimeField); + wRowTimeField.addModifyListener(lsMod); + FormData fdRowTimeField = new FormData(); + fdRowTimeField.left = new FormAttachment(middle, 0); + fdRowTimeField.top = new FormAttachment(lastControl, margin); + fdRowTimeField.right = new FormAttachment(100, 0); + wRowTimeField.setLayoutData(fdRowTimeField); + lastControl = wRowTimeField; + + wlLastTimeField = new Label(shell, SWT.RIGHT); + wlLastTimeField.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.LastTimeField.Label")); + props.setLook(wlLastTimeField); + FormData fdlLastTimeField = new FormData(); + fdlLastTimeField.left = new FormAttachment(0, 0); + fdlLastTimeField.right = new FormAttachment(middle, -margin); + fdlLastTimeField.top = new FormAttachment(lastControl, margin); + wlLastTimeField.setLayoutData(fdlLastTimeField); + wLastTimeField = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wLastTimeField); + wLastTimeField.addModifyListener(lsMod); + FormData fdLastTimeField = new FormData(); + fdLastTimeField.left = new FormAttachment(middle, 0); + fdLastTimeField.top = new FormAttachment(lastControl, margin); + fdLastTimeField.right = new FormAttachment(100, 0); + wLastTimeField.setLayoutData(fdLastTimeField); + lastControl = wLastTimeField; + + wOk = new Button(shell, SWT.PUSH); + wOk.setText(BaseMessages.getString(PKG, "System.Button.OK")); + wOk.addListener(SWT.Selection, e -> ok()); + wPreview = new Button(shell, SWT.PUSH); + wPreview.setText(BaseMessages.getString(PKG, "System.Button.Preview")); + wPreview.addListener(SWT.Selection, e -> preview()); + wCancel = new Button(shell, SWT.PUSH); + wCancel.setText(BaseMessages.getString(PKG, "System.Button.Cancel")); + wCancel.addListener(SWT.Selection, e -> cancel()); + + setButtonPositions(new Button[] {wOk, wPreview, wCancel}, margin, null); + + Label wlFields = new Label(shell, SWT.NONE); + wlFields.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Fields.Label")); + props.setLook(wlFields); + FormData fdlFields = new FormData(); + fdlFields.left = new FormAttachment(0, 0); + fdlFields.top = new FormAttachment(lastControl, margin); + wlFields.setLayoutData(fdlFields); + lastControl = wlFields; + + final int nrFields = input.getFields().size(); + + ColumnInfo[] colinf = + new ColumnInfo[] { + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Name"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Fields.Item"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Type"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + ValueMetaFactory.getValueMetaNames()), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Format"), + ColumnInfo.COLUMN_TYPE_FORMAT, + 2), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Length"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Precision"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Currency"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Decimal"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Group"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Value"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.SetEmptyString"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + new String[] { + BaseMessages.getString(PKG, "System.Combo.Yes"), + BaseMessages.getString(PKG, "System.Combo.No") + }) + }; + + wFields = + new TableView( + variables, + shell, + SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI, + colinf, + nrFields, + lsMod, + props); + + FormData fdFields = new FormData(); + fdFields.left = new FormAttachment(0, 0); + fdFields.top = new FormAttachment(lastControl, margin); + fdFields.right = new FormAttachment(100, 0); + fdFields.bottom = new FormAttachment(wOk, -2 * margin); + wFields.setLayoutData(fdFields); + + lsResize = + event -> { + Point size = shell.getSize(); + wFields.setSize(size.x - 10, size.y - 50); + wFields.table.setSize(size.x - 10, size.y - 50); + wFields.redraw(); + }; + */ + + //shell.addListener(SWT.Resize, lsResize); + + getData(); + input.setChanged(changed); + + BaseDialog.defaultShellHandling(shell, c -> ok(), c -> cancel()); + + return transformName; + }; + + + public void setActive() { + boolean neverEnding = wNeverEnding.getSelection(); + + wlLimit.setEnabled(!neverEnding); + wLimit.setEnabled(!neverEnding); + } + + + + private Image getImage() { + return SwtSvgImageUtil.getImage( shell.getDisplay(), getClass().getClassLoader(), "plc4x_toddy_read.svg", ConstUi.LARGE_ICON_SIZE, + ConstUi.LARGE_ICON_SIZE ); + } + + /** + * Copy information from the meta-data input to the dialog fields. + * + */ + public void getData() { + if (isDebug()) { + logDebug("getting fields info..."); + } + if (input.getConnection() == null) { + wConnection.setText(""); + } else { + wConnection.setText(input.getConnection()); + } + + wLimit.setText(input.getRowLimit()); + wNeverEnding.setSelection(input.isNeverEnding()); + + + setActive(); + + wTransformName.selectAll(); + wTransformName.setFocus(); + } + + /** + * Stores the information from the dialog box in meta-data. + * + * @param meta + */ + private void getInfo( Plc4xEventMeta meta) throws HopException { + meta.setConnection(wConnection.getText()); + meta.setRowLimit(wLimit.getText()); + meta.setNeverEnding(wNeverEnding.getSelection()); + + } + + /** + * Cancel the dialog. + */ + private void cancel() { + transformName = null; + input.setChanged( changed ); + dispose(); + } + + private void ok() { + if (Utils.isEmpty(wTransformName.getText())) { + return; + } + + transformName = wTransformName.getText(); // return value + try { + getInfo(new Plc4xEventMeta()); // to see if there is an exception + getInfo(input); // to put the content on the input structure for real if all is well. + dispose(); + } catch (HopException e) { + new ErrorDialog( + shell, + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title"), + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message"), + e); + } + } + + + /** + * Preview the data generated by this transform. This generates a pipeline using this transform & + * a dummy and previews it. + */ + private void preview() { + Plc4xEventMeta oneMeta = new Plc4xEventMeta(); + try { + getInfo(oneMeta); + } catch (HopException e) { + new ErrorDialog( + shell, + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title"), + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message"), + e); + return; + } + + PipelineMeta previewMeta = + PipelinePreviewFactory.generatePreviewPipeline( + pipelineMeta.getMetadataProvider(), oneMeta, wTransformName.getText()); + + EnterNumberDialog numberDialog = + new EnterNumberDialog( + shell, + props.getDefaultPreviewSize(), + BaseMessages.getString(PKG, "System.Dialog.EnterPreviewSize.Title"), + BaseMessages.getString(PKG, "System.Dialog.EnterPreviewSize.Message")); + int previewSize = numberDialog.open(); + if (previewSize > 0) { + PipelinePreviewProgressDialog progressDialog = + new PipelinePreviewProgressDialog( + shell, + variables, + previewMeta, + new String[] {wTransformName.getText()}, + new int[] {previewSize}); + progressDialog.open(); + + Pipeline pipeline = progressDialog.getPipeline(); + String loggingText = progressDialog.getLoggingText(); + + if (!progressDialog.isCancelled()) { + if (pipeline.getResult() != null && pipeline.getResult().getNrErrors() > 0) { + EnterTextDialog etd = + new EnterTextDialog( + shell, + BaseMessages.getString(PKG, "System.Dialog.PreviewError.Title"), + BaseMessages.getString(PKG, "System.Dialog.PreviewError.Message"), + loggingText, + true); + etd.setReadOnly(); + etd.open(); + } + } + + PreviewRowsDialog prd = + new PreviewRowsDialog( + shell, + variables, + SWT.NONE, + wTransformName.getText(), + progressDialog.getPreviewRowsMeta(wTransformName.getText()), + progressDialog.getPreviewRows(wTransformName.getText()), + loggingText); + prd.open(); + } + } + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventMeta.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventMeta.java new file mode 100644 index 00000000000..207adb78245 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventMeta.java @@ -0,0 +1,239 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xevent; + +import java.util.ArrayList; +import org.apache.hop.core.ICheckResult; +import org.apache.hop.core.annotations.Transform; +import org.apache.hop.core.exception.HopTransformException; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.metadata.api.IHopMetadataProvider; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.transform.BaseTransformMeta; +import org.apache.hop.pipeline.transform.ITransformMeta; +import org.apache.hop.pipeline.transform.TransformMeta; + +import java.util.List; +import org.apache.hop.core.Const; +import org.apache.hop.core.RowMetaAndData; +import org.apache.hop.core.row.IValueMeta; +import org.apache.hop.metadata.api.HopMetadataProperty; +import org.apache.hop.pipeline.transform.ITransformIOMeta; +import org.apache.hop.pipeline.transform.TransformIOMeta; + +/** + * Meta data for the sample transform. + */ +@Transform( + id = "plc4x-event", + name = "i18n::Plc4x.Read.Name", + description = "i18n::Plc4x.Read.Description", + image = "plc4x_event.svg", + categoryDescription = "i18n:org.apache.plc4x.hop.transforms.plc4xevent:Plc4x.Category.plc4x", + documentationUrl = "https://plc4x.apache.org/users/integrations/apache-hop.html" +) +public class Plc4xEventMeta extends BaseTransformMeta implements ITransformMeta { + + private static final Class PKG = Plc4xEventMeta.class; // Needed by Translator + + + @HopMetadataProperty( + key = "connection", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.Connection") + private String connection; + + @HopMetadataProperty( + key = "limit", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.RowLimit") + private String rowLimit; + + @HopMetadataProperty( + key = "never_ending", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.NeverEnding") + private boolean neverEnding; + + @HopMetadataProperty( + key = "never_ending", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.NeverEnding") + private boolean modeEvent; + + @HopMetadataProperty( + key = "never_ending", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.NeverEnding") + private boolean userEvent; + + @HopMetadataProperty( + key = "never_ending", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.NeverEnding") + private boolean sysEvent; + + @HopMetadataProperty( + key = "never_ending", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.NeverEnding") + private boolean alarmEvent; + + + public Plc4xEventMeta() { + rowLimit = "10"; + neverEnding = false; + modeEvent = false; + userEvent = false; + sysEvent = false; + alarmEvent = false; + + } + + public Plc4xEventMeta(Plc4xEventMeta m) { + this.connection = m.connection; + this.neverEnding = m.neverEnding; + this.modeEvent = m.modeEvent; + this.userEvent = m.userEvent; + this.sysEvent = m.sysEvent; + this.alarmEvent = m.alarmEvent; + } + + @Override + public Plc4xEventMeta clone() { + return new Plc4xEventMeta(this); + } + + + + @Override + public void getFields( IRowMeta inputRowMeta, String name, IRowMeta[] info, TransformMeta nextTransform, + IVariables variables, IHopMetadataProvider metadataProvider ) throws HopTransformException { + try { + List remarks = new ArrayList<>(); + RowMetaAndData rowMetaAndData = Plc4xEvent.buildRow(this, remarks, name); + if (!remarks.isEmpty()) { + StringBuilder stringRemarks = new StringBuilder(); + for (ICheckResult remark : remarks) { + stringRemarks.append(remark.toString()).append(Const.CR); + } + throw new HopTransformException(stringRemarks.toString()); + } + for (IValueMeta valueMeta : rowMetaAndData.getRowMeta().getValueMetaList()) { + valueMeta.setOrigin(name); + } + inputRowMeta.mergeRowMeta(rowMetaAndData.getRowMeta()); + } catch (Exception e) { + throw new HopTransformException(e); + } + } + + public Plc4xEvent createTransform(TransformMeta transformMeta, Plc4xEventData data, int copyNr, + PipelineMeta pipelineMeta, Pipeline pipeline ) { + return new Plc4xEvent( transformMeta, this, data, copyNr, pipelineMeta, pipeline ); + } + + /** + * + * @return + */ + public Plc4xEventData getTransformData() { + return new Plc4xEventData(); + } + + @Override + public void setDefault() { + //default values when creating a new transform + } + + + /** + * Returns the Input/Output metadata for this transform. + * The generator transform only produces output, does not accept input! + * TransformIOMeta(inputAcceptor, outputProducer, inputOptional, outputDynamic, inputDynamic) + */ + @Override + public ITransformIOMeta getTransformIOMeta() { + return new TransformIOMeta(false, true, false, false, false, false); + } + + /** + * Gets Plc4xConnection metadata name. + * + * @return value of intervalInMs + */ + public String getConnection() { + return connection; + } + + /** @param connection */ + public void setConnection(String connection) { + this.connection = connection; + } + + public String getRowLimit() { + return rowLimit; + } + + /** @param connection */ + public void setRowLimit(String rowLimit) { + this.rowLimit = rowLimit; + } + + /** + * Gets neverEnding + * + * @return value of neverEnding + */ + public boolean isNeverEnding() { + return neverEnding; + } + + /** @param neverEnding The neverEnding to set */ + public void setNeverEnding(boolean neverEnding) { + this.neverEnding = neverEnding; + } + + public boolean isModeEvent() { + return neverEnding; + } + + public void setModeEvent(boolean modeEvent) { + this.modeEvent = modeEvent; + } + + public boolean isUserEvent() { + return neverEnding; + } + + public void setUserEvent(boolean userEvent) { + this.userEvent = userEvent; + } + + public boolean isSysEvent() { + return sysEvent; + } + + public void setSysEvent(boolean sysEvent) { + this.sysEvent = sysEvent; + } + + public boolean isAlarmEvent() { + return alarmEvent; + } + + public void setAlarmEvent(boolean alarmEvent) { + this.alarmEvent = alarmEvent; + } + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xRead.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xRead.java new file mode 100644 index 00000000000..7b1832c16d1 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xRead.java @@ -0,0 +1,446 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xinput; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; +import org.apache.commons.lang3.StringUtils; +import org.apache.hop.core.CheckResult; +import org.apache.hop.core.Const; +import org.apache.hop.core.ICheckResult; +import org.apache.hop.core.RowMetaAndData; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.exception.HopPluginException; +import org.apache.hop.core.exception.HopValueException; +import org.apache.hop.core.logging.LogLevel; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.row.IValueMeta; +import org.apache.hop.core.row.RowDataUtil; +import org.apache.hop.core.row.RowMeta; +import org.apache.hop.core.row.value.ValueMetaDate; +import org.apache.hop.core.row.value.ValueMetaFactory; +import org.apache.hop.core.util.StringUtil; +import org.apache.hop.core.util.Utils; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.metadata.api.IHopMetadataProvider; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.transform.BaseTransform; +import org.apache.hop.pipeline.transform.ITransform; +import org.apache.hop.pipeline.transform.TransformMeta; +import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.apache.plc4x.hop.transforms.util.Plc4xGeneratorField; +import org.apache.plc4x.hop.transforms.util.Plc4xPlcField; +import org.apache.plc4x.hop.transforms.util.Plc4xWrapperConnection; +import org.apache.plc4x.java.DefaultPlcDriverManager; +import org.apache.plc4x.java.api.PlcConnection; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.messages.PlcReadResponse; + +/** + * Transform That contains the basic skeleton needed to create your own plugin + * + */ +public class Plc4xRead extends BaseTransform implements ITransform { + + private static final Class PKG = Plc4xRead.class; // Needed by Translator + + private Plc4xConnection connmeta = null; + private Plc4xWrapperConnection connwrapper = null; + private PlcReadRequest readRequest = null; + private PlcReadResponse readResponse = null; + private int maxwait = 0; + private static final ReentrantLock lock = new ReentrantLock(); + + private static final String dummy = "dummy"; + + private Map index = new HashMap(); + private Map plcfields = new HashMap(); + + public Plc4xRead(TransformMeta transformMeta, Plc4xReadMeta meta, Plc4xReadData data, int copyNr, PipelineMeta pipelineMeta, + Pipeline pipeline ) { + super( transformMeta, meta, data, copyNr, pipelineMeta, pipeline ); + } + + /* + * Including Date and Time field for every row + * + * @param meta Meta data from user dialog + * @param remarks Error registers + * @param origin transform instance name + */ + public static final RowMetaAndData buildRow( + Plc4xReadMeta meta, List remarks, String origin) throws HopPluginException { + IRowMeta rowMeta = new RowMeta(); + Object[] rowData = RowDataUtil.allocateRowData(meta.getFields().size() + 2); + int index = 0; + + if (!Utils.isEmpty(meta.getRowTimeField())) { + rowMeta.addValueMeta(new ValueMetaDate(meta.getRowTimeField())); + rowData[index++] = null; + } + + if (!Utils.isEmpty(meta.getLastTimeField())) { + rowMeta.addValueMeta(new ValueMetaDate(meta.getLastTimeField())); + rowData[index++] = null; + } + + for (Plc4xGeneratorField field : meta.getFields()) { + int typeString = ValueMetaFactory.getIdForValueMeta(field.getType()); + if (StringUtils.isNotEmpty(field.getType())) { + System.out.println("typeString: " + typeString); + IValueMeta valueMeta = + ValueMetaFactory.createValueMeta(field.getName(), typeString); // build a + // value! + valueMeta.setLength(field.getLength()); + valueMeta.setPrecision(field.getPrecision()); + valueMeta.setConversionMask(field.getFormat()); + valueMeta.setCurrencySymbol(field.getCurrency()); + valueMeta.setGroupingSymbol(field.getGroup()); + valueMeta.setDecimalSymbol(field.getDecimal()); + valueMeta.setOrigin(origin); + + IValueMeta stringMeta = ValueMetaFactory.cloneValueMeta(valueMeta, IValueMeta.TYPE_STRING); + + if (field.isSetEmptyString()) { + // Set empty string + rowData[index] = StringUtil.EMPTY_STRING; + } else { + String stringValue = field.getValue(); + + // If the value is empty: consider it to be NULL. + if (Utils.isEmpty(stringValue)) { + rowData[index] = null; + + if (valueMeta.getType() == IValueMeta.TYPE_NONE) { + String message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.CheckResult.SpecifyTypeError", + valueMeta.getName(), + stringValue); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + } + } else { + // Convert the data from String to the specified type ... + // + try { + System.out.println("stringValue: " + stringValue); + rowData[index] = valueMeta.convertData(stringMeta, stringValue); + } catch (HopValueException e) { + switch (valueMeta.getType()) { + case IValueMeta.TYPE_NUMBER: + String message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.Number", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + case IValueMeta.TYPE_DATE: + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.Date", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + case IValueMeta.TYPE_INTEGER: + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.Integer", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + case IValueMeta.TYPE_BIGNUMBER: + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.BigNumber", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + case IValueMeta.TYPE_TIMESTAMP: + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.Timestamp", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + default: + // Boolean and binary don't throw errors normally, so it's probably an unspecified + // error problem... + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.CheckResult.SpecifyTypeError", + valueMeta.getName(), + stringValue); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + } + } + } + } + + // Now add value to the row! + // This is in fact a copy from the fields row, but now with data. + rowMeta.addValueMeta(valueMeta); + index++; + } + } + + return new RowMetaAndData(rowMeta, rowData); + } + + /* + * 1. Block the other instances by means of a lock. + * 2. Try to locate an existing connection. + * 3. If it doesn't exist, it tries to take control of the routine to + * create an instance of PlcConnection and his wrapper. + * 4. Register the connection wrapper for global access. + * 5. If the connection to the PLC is made, then it creates the query + * and executes it. + * + */ + @Override + public boolean processRow() throws HopException { + Object[] r = getRow(); // Get row from input rowset & set row busy! + setLogLevel(LogLevel.DEBUG); + + if ((!meta.isNeverEnding() && data.rowsWritten >= data.rowLimit) && !isStopped()) { + setOutputDone(); // signal end to receiver(s) + return false; + } + + if (first) { + index.clear(); + plcfields.clear(); + //This performs a minimal check on the user item. + //It guarantees that the rates are within those managed by Plc4x. + meta.getFields().forEach((f) ->{ + plcfields.put(f.getName(),Plc4xPlcField.of(f.getItem())); + }); + first = false; + } + + lock.lock(); //(01) + try { + IHopMetadataProvider metaprovider = getMetadataProvider(); + connmeta = metaprovider.getSerializer(Plc4xConnection.class).load(meta.getConnection()); + if (connwrapper == null) { + connwrapper = (Plc4xWrapperConnection) getPipeline().getExtensionDataMap().get(meta.getConnection()); //(02) + if (connwrapper != null) connwrapper.retain(); + }; + + if (connmeta == null){ + logError( + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.Log.SetMetadata", + meta.getConnection())); + } + + if ((connmeta != null) && (connwrapper == null)){ + readRequest = null; + try{ + PlcConnection conn = new DefaultPlcDriverManager().getConnection(connmeta.getUrl()); //(03) + if (conn.isConnected()) { + connwrapper = new Plc4xWrapperConnection(conn); + getPipeline().getExtensionDataMap().put(meta.getConnection(), connwrapper); //(04) + } + } catch (Exception ex){ + setErrors(1L); + logError("Unable to create connection to PLC. " + ex.getMessage()); + } + } + } finally { + lock.unlock(); + } + + if ((connmeta != null) && (connwrapper != null)){ + if (connwrapper.getConnection().isConnected()){ + if (readRequest == null){ + PlcReadRequest.Builder builder = connwrapper.getConnection().readRequestBuilder(); //(05) + for (Plc4xGeneratorField field: meta.getFields()){ + builder.addTagAddress(field.getName(), field.getItem()); + } + readRequest = builder.build(); + } + try { + maxwait = Integer.parseInt(meta.getMaxwaitInMs()); + maxwait = (maxwait<100)?100:maxwait; + readResponse = readRequest.execute().get(maxwait, TimeUnit.MILLISECONDS); + + for (Plc4xGeneratorField field: meta.getFields()){ + field.setValue(readResponse.getString(field.getName())); + } + } catch (Exception ex) { + setErrors(1L); + logError("Unable read from PLC. " + ex.getMessage()); + } + + } else { + setErrors(1L); + logError("PLC is not connected."); + setOutputDone(); + return false; + } + + } else { + setErrors(1L); + logError("PLC connection don't exist."); + setOutputDone(); + return false; + } + + // + int interval = Integer.parseInt(meta.getIntervalInMs()); + + try { + Thread.sleep(interval); + } catch (InterruptedException ex) { + setErrors(1L); + logError(ex.getMessage()); + } + + r = data.outputRowMeta.cloneRow(data.outputRowData); + logBasic("Tamano de los datos: " + r.length); + data.prevDate = data.rowDate; + data.rowDate = new Date(); + int index = 0; + if (!Utils.isEmpty(meta.getRowTimeField())) { + r[index++] = data.rowDate; + } + if (!Utils.isEmpty(meta.getLastTimeField())) { + r[index++] = data.prevDate; + } + for (Plc4xGeneratorField field: meta.getFields()){ + if (field.getType().equalsIgnoreCase("Boolean")){ + r[index++] = Boolean.parseBoolean(field.getValue()); + } else if (field.getType().equalsIgnoreCase("Number")){ + r[index++] = Double.parseDouble(field.getValue()); + } else if (field.getType().equalsIgnoreCase("Integer")){ + r[index++] = Integer.parseInt(field.getValue()); + } + } + putRow(data.outputRowMeta, r ); // return your data + data.rowsWritten++; + return true; + } + + + @Override + public boolean init() { + try { + if(super.init()){ + // Determine the number of rows to generate... + data.rowLimit = Const.toLong(resolve(meta.getRowLimit()), -1L); + data.rowsWritten = 0L; + data.delay = Const.toLong(resolve(meta.getIntervalInMs()), -1L); + + if (data.rowLimit < 0L) { // Unable to parse + logError(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Wrong.RowLimit.Number")); + return false; // fail + } + + // Create a row (constants) with all the values in it... + List remarks = new ArrayList<>(); // stores the errors... + RowMetaAndData outputRow = buildRow(meta, remarks, getTransformName()); + if (!remarks.isEmpty()) { + for (int i = 0; i < remarks.size(); i++) { + CheckResult cr = (CheckResult) remarks.get(i); + logError(cr.getText()); + } + return false; + } + + data.outputRowData = outputRow.getData(); + data.outputRowMeta = outputRow.getRowMeta(); + + return true; + } + return false; + } catch (Exception ex){ + setErrors(1L); + logError("Error initializing transform", ex); + return false; + } + } + + /* + * Here, must perform the cleaning of any resource, main of the connection to + * the associated PLC. + */ + @Override + public void cleanup() { + super.cleanup(); + logBasic("Cleanup. Release connection."); + if (connwrapper != null) + connwrapper.release(); + } + + + /* + * Here, must perform the cleaning of any resource. + * 1. Check if we have reference to wrapper. + * 2. Release de reference to object. + * 3. The lastone remove the global reference to connection wrapper. + * 4. Clear local references. + */ + @Override + public void dispose() { + super.dispose(); + if (connwrapper != null) { + logBasic("Dispose. Release connection: " + connwrapper.refCnt()); + connwrapper.release(); + if (!connwrapper.getConnection().isConnected()){ + getPipeline().getExtensionDataMap().remove(meta.getConnection()); + } + connwrapper = null; + readRequest = null; + + } + } + + + + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadData.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadData.java new file mode 100644 index 00000000000..98b5889f0a8 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadData.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xinput; + +import java.util.Date; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.pipeline.transform.BaseTransformData; +import org.apache.hop.pipeline.transform.ITransformData; + + +public class Plc4xReadData extends BaseTransformData implements ITransformData { + + //The Plc4xConnection metadata + public String connection; + + public IRowMeta outputRowMeta; + public Object[] outputRowData; + + public long rowLimit; + public long rowsWritten; + public Date rowDate; + public Date prevDate; + public long delay; + + + + /** + * Default constructor for SampleData. + */ + public Plc4xReadData() { + super(); + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadDialog.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadDialog.java new file mode 100644 index 00000000000..a736e418da0 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadDialog.java @@ -0,0 +1,600 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xinput; + +import org.apache.hop.core.Const; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.row.value.ValueMetaFactory; +import org.apache.hop.core.util.Utils; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.PipelinePreviewFactory; +import org.apache.hop.pipeline.transform.BaseTransformMeta; +import org.apache.hop.pipeline.transform.ITransformDialog; +import org.apache.hop.ui.core.ConstUi; +import org.apache.hop.ui.core.dialog.BaseDialog; +import org.apache.hop.ui.core.dialog.EnterNumberDialog; +import org.apache.hop.ui.core.dialog.EnterTextDialog; +import org.apache.hop.ui.core.dialog.ErrorDialog; +import org.apache.hop.ui.core.dialog.PreviewRowsDialog; +import org.apache.hop.ui.core.widget.ColumnInfo; +import org.apache.hop.ui.core.widget.MetaSelectionLine; +import org.apache.hop.ui.core.widget.TableView; +import org.apache.hop.ui.core.widget.TextVar; +import org.apache.hop.ui.pipeline.dialog.PipelinePreviewProgressDialog; +import org.apache.hop.ui.pipeline.transform.BaseTransformDialog; +import org.apache.hop.ui.util.SwtSvgImageUtil; +import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.apache.plc4x.hop.transforms.util.Plc4xGeneratorField; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.*; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; + +public class Plc4xReadDialog extends BaseTransformDialog implements ITransformDialog { + private static final Class PKG = Plc4xReadDialog.class; // Needed by Translator + + private MetaSelectionLine wConnection; + + private Label wlLimit; + private TextVar wLimit; + + private Button wNeverEnding; + + private Label wlMaxwait; + private TextVar wMaxwait; + + private Label wlInterval; + private TextVar wInterval; + + private Label wlRowTimeField; + private TextVar wRowTimeField; + + private Label wlLastTimeField; + private TextVar wLastTimeField; + + private TableView wFields; + + private final Plc4xReadMeta input; + + public Plc4xReadDialog(Shell parent, IVariables variables , Object in, PipelineMeta pipelineMeta, String sname ) { + super( parent, variables, (BaseTransformMeta) in, pipelineMeta, sname ); + input = (Plc4xReadMeta) in; + } + + @Override + public String open() { + Shell parent = getParent(); + + shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX | SWT.MIN); + props.setLook(shell); + setShellImage(shell, input); + + ModifyListener lsMod = e -> input.setChanged(); + changed = input.hasChanged(); + + FormLayout formLayout = new FormLayout(); + formLayout.marginWidth = Const.FORM_MARGIN; + formLayout.marginHeight = Const.FORM_MARGIN; + + shell.setLayout(formLayout); + shell.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.DialogTitle")); + + int middle = props.getMiddlePct(); + int margin = props.getMargin(); + + // Filename line + wlTransformName = new Label(shell, SWT.RIGHT); + wlTransformName.setText(BaseMessages.getString(PKG, "System.Label.TransformName")); + props.setLook(wlTransformName); + fdlTransformName = new FormData(); + fdlTransformName.left = new FormAttachment(0, 0); + fdlTransformName.right = new FormAttachment(middle, -margin); + fdlTransformName.top = new FormAttachment(0, margin); + wlTransformName.setLayoutData(fdlTransformName); + + wTransformName = new Text(shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + wTransformName.setText(transformName); + props.setLook(wTransformName); + wTransformName.addModifyListener(lsMod); + fdTransformName = new FormData(); + fdTransformName.left = new FormAttachment(middle, 0); + fdTransformName.top = new FormAttachment(0, margin); + fdTransformName.right = new FormAttachment(100, 0); + wTransformName.setLayoutData(fdTransformName); + + // Connection line + wConnection = + new MetaSelectionLine<>( + variables, + metadataProvider, + Plc4xConnection.class, + shell, + SWT.NONE, + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Connection.Label"), + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Connection.Tooltip")); + FormData fdConnection = new FormData(); + fdConnection.left = new FormAttachment(0, 0); + fdConnection.right = new FormAttachment(100, 0); + fdConnection.top = new FormAttachment(wTransformName, margin); + wConnection.setLayoutData(fdConnection); + props.setLook(wConnection); + try { + wConnection.fillItems(); + } catch (Exception e) { + new ErrorDialog(shell, "Error", "Error listing Cassandra connection metadata objects", e); + } + + Control lastControl = wConnection; + + wlLimit = new Label(shell, SWT.RIGHT); + wlLimit.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Limit.Label")); + props.setLook(wlLimit); + FormData fdlLimit = new FormData(); + fdlLimit.left = new FormAttachment(0, 0); + fdlLimit.right = new FormAttachment(middle, -margin); + fdlLimit.top = new FormAttachment(lastControl, margin); + wlLimit.setLayoutData(fdlLimit); + wLimit = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wLimit); + wLimit.addModifyListener(lsMod); + FormData fdLimit = new FormData(); + fdLimit.left = new FormAttachment(middle, 0); + fdLimit.top = new FormAttachment(lastControl, margin); + fdLimit.right = new FormAttachment(100, 0); + wLimit.setLayoutData(fdLimit); + lastControl = wLimit; + + Label wlNeverEnding = new Label(shell, SWT.RIGHT); + wlNeverEnding.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.NeverEnding.Label")); + props.setLook(wlNeverEnding); + FormData fdlNeverEnding = new FormData(); + fdlNeverEnding.left = new FormAttachment(0, 0); + fdlNeverEnding.right = new FormAttachment(middle, -margin); + fdlNeverEnding.top = new FormAttachment(lastControl, margin); + wlNeverEnding.setLayoutData(fdlNeverEnding); + wNeverEnding = new Button(shell, SWT.CHECK); + props.setLook(wNeverEnding); + wNeverEnding.addSelectionListener( + new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + setActive(); + input.setChanged(); + } + }); + FormData fdNeverEnding = new FormData(); + fdNeverEnding.left = new FormAttachment(middle, 0); + fdNeverEnding.top = new FormAttachment(wlNeverEnding, 0, SWT.CENTER); + fdNeverEnding.right = new FormAttachment(100, 0); + wNeverEnding.setLayoutData(fdNeverEnding); + lastControl = wlNeverEnding; + + wlMaxwait = new Label(shell, SWT.RIGHT); + wlMaxwait.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Maxwait.Label")); + props.setLook(wlMaxwait); + FormData fdlMaxwait = new FormData(); + fdlMaxwait.left = new FormAttachment(0, 0); + fdlMaxwait.right = new FormAttachment(middle, -margin); + fdlMaxwait.top = new FormAttachment(lastControl, margin); + wlMaxwait.setLayoutData(fdlMaxwait); + wMaxwait = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wMaxwait); + wMaxwait.addModifyListener(lsMod); + FormData fdMaxwait = new FormData(); + fdMaxwait.left = new FormAttachment(middle, 0); + fdMaxwait.top = new FormAttachment(lastControl, margin); + fdMaxwait.right = new FormAttachment(100, 0); + wMaxwait.setLayoutData(fdMaxwait); + lastControl = wMaxwait; + + wlInterval = new Label(shell, SWT.RIGHT); + wlInterval.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Interval.Label")); + props.setLook(wlInterval); + FormData fdlInterval = new FormData(); + fdlInterval.left = new FormAttachment(0, 0); + fdlInterval.right = new FormAttachment(middle, -margin); + fdlInterval.top = new FormAttachment(lastControl, margin); + wlInterval.setLayoutData(fdlInterval); + wInterval = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wInterval); + wInterval.addModifyListener(lsMod); + FormData fdInterval = new FormData(); + fdInterval.left = new FormAttachment(middle, 0); + fdInterval.top = new FormAttachment(lastControl, margin); + fdInterval.right = new FormAttachment(100, 0); + wInterval.setLayoutData(fdInterval); + lastControl = wInterval; + + /* + wlRowTimeField = new Label(shell, SWT.RIGHT); + wlRowTimeField.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.RowTimeField.Label")); + props.setLook(wlRowTimeField); + FormData fdlRowTimeField = new FormData(); + fdlRowTimeField.left = new FormAttachment(0, 0); + fdlRowTimeField.right = new FormAttachment(middle, -margin); + fdlRowTimeField.top = new FormAttachment(lastControl, margin); + wlRowTimeField.setLayoutData(fdlRowTimeField); + wRowTimeField = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wRowTimeField); + wRowTimeField.addModifyListener(lsMod); + FormData fdRowTimeField = new FormData(); + fdRowTimeField.left = new FormAttachment(middle, 0); + fdRowTimeField.top = new FormAttachment(lastControl, margin); + fdRowTimeField.right = new FormAttachment(100, 0); + wRowTimeField.setLayoutData(fdRowTimeField); + lastControl = wRowTimeField; + + wlLastTimeField = new Label(shell, SWT.RIGHT); + wlLastTimeField.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.LastTimeField.Label")); + props.setLook(wlLastTimeField); + FormData fdlLastTimeField = new FormData(); + fdlLastTimeField.left = new FormAttachment(0, 0); + fdlLastTimeField.right = new FormAttachment(middle, -margin); + fdlLastTimeField.top = new FormAttachment(lastControl, margin); + wlLastTimeField.setLayoutData(fdlLastTimeField); + wLastTimeField = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wLastTimeField); + wLastTimeField.addModifyListener(lsMod); + FormData fdLastTimeField = new FormData(); + fdLastTimeField.left = new FormAttachment(middle, 0); + fdLastTimeField.top = new FormAttachment(lastControl, margin); + fdLastTimeField.right = new FormAttachment(100, 0); + wLastTimeField.setLayoutData(fdLastTimeField); + lastControl = wLastTimeField; + */ + wOk = new Button(shell, SWT.PUSH); + wOk.setText(BaseMessages.getString(PKG, "System.Button.OK")); + wOk.addListener(SWT.Selection, e -> ok()); + wPreview = new Button(shell, SWT.PUSH); + wPreview.setText(BaseMessages.getString(PKG, "System.Button.Preview")); + wPreview.addListener(SWT.Selection, e -> preview()); + wCancel = new Button(shell, SWT.PUSH); + wCancel.setText(BaseMessages.getString(PKG, "System.Button.Cancel")); + wCancel.addListener(SWT.Selection, e -> cancel()); + + setButtonPositions(new Button[] {wOk, wPreview, wCancel}, margin, null); + + Label wlFields = new Label(shell, SWT.NONE); + wlFields.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Fields.Label")); + props.setLook(wlFields); + FormData fdlFields = new FormData(); + fdlFields.left = new FormAttachment(0, 0); + fdlFields.top = new FormAttachment(lastControl, margin); + wlFields.setLayoutData(fdlFields); + lastControl = wlFields; + + final int nrFields = input.getFields().size(); + + ColumnInfo[] colinf = + new ColumnInfo[] { + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Name"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Fields.Item"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Type"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + ValueMetaFactory.getValueMetaNames()), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Format"), + ColumnInfo.COLUMN_TYPE_FORMAT, + 2), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Length"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Precision"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Currency"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Decimal"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Group"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Value"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.SetEmptyString"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + new String[] { + BaseMessages.getString(PKG, "System.Combo.Yes"), + BaseMessages.getString(PKG, "System.Combo.No") + }) + }; + + wFields = + new TableView( + variables, + shell, + SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI, + colinf, + nrFields, + lsMod, + props); + + FormData fdFields = new FormData(); + fdFields.left = new FormAttachment(0, 0); + fdFields.top = new FormAttachment(lastControl, margin); + fdFields.right = new FormAttachment(100, 0); + fdFields.bottom = new FormAttachment(wOk, -2 * margin); + wFields.setLayoutData(fdFields); + + lsResize = + event -> { + Point size = shell.getSize(); + wFields.setSize(size.x - 10, size.y - 50); + wFields.table.setSize(size.x - 10, size.y - 50); + wFields.redraw(); + }; + shell.addListener(SWT.Resize, lsResize); + + getData(); + input.setChanged(changed); + + BaseDialog.defaultShellHandling(shell, c -> ok(), c -> cancel()); + + return transformName; + }; + + @Override + public void setActive() { + boolean neverEnding = wNeverEnding.getSelection(); + + wlLimit.setEnabled(!neverEnding); + wLimit.setEnabled(!neverEnding); + + //wlInterval.setEnabled(neverEnding); + //wInterval.setEnabled(neverEnding); + + //wlRowTimeField.setEnabled(neverEnding); + //wRowTimeField.setEnabled(neverEnding); + + //wlLastTimeField.setEnabled(neverEnding); + //wLastTimeField.setEnabled(neverEnding); + } + + + + private Image getImage() { + return SwtSvgImageUtil.getImage( shell.getDisplay(), getClass().getClassLoader(), "plc4x_toddy_read.svg", ConstUi.LARGE_ICON_SIZE, + ConstUi.LARGE_ICON_SIZE ); + } + + /** + * Copy information from the meta-data input to the dialog fields. + * + */ + public void getData() { + if (isDebug()) { + logDebug("getting fields info..."); + } + if (input.getConnection() == null) { + wConnection.setText(""); + } else { + wConnection.setText(input.getConnection()); + } + + wLimit.setText(input.getRowLimit()); + wNeverEnding.setSelection(input.isNeverEnding()); + wMaxwait.setText(Const.NVL(input.getMaxwaitInMs(), "")); + wInterval.setText(Const.NVL(input.getIntervalInMs(), "")); + // wRowTimeField.setText(Const.NVL(input.getRowTimeField(), "")); + //wLastTimeField.setText(Const.NVL(input.getLastTimeField(), "")); + + for (int i = 0; i < input.getFields().size(); i++) { + Plc4xGeneratorField field = input.getFields().get(i); + TableItem item = wFields.table.getItem(i); + int col = 1; + item.setText(col++, Const.NVL(field.getName(), "")); + + item.setText(col++, Const.NVL(field.getItem(), "")); + + String type = field.getType(); + String format = field.getFormat(); + String length = field.getLength() < 0 ? "" : ("" + field.getLength()); + String prec = field.getPrecision() < 0 ? "" : ("" + field.getPrecision()); + + String curr = field.getCurrency(); + String group = field.getGroup(); + String decim = field.getDecimal(); + String def = field.getValue(); + + item.setText(col++, Const.NVL(type, "")); + item.setText(col++, Const.NVL(format, "")); + item.setText(col++, Const.NVL(length, "")); + item.setText(col++, Const.NVL(prec, "")); + item.setText(col++, Const.NVL(curr, "")); + item.setText(col++, Const.NVL(decim, "")); + item.setText(col++, Const.NVL(group, "")); + item.setText(col++, Const.NVL(def, "")); + item.setText( + col++, + field.isSetEmptyString() + ? BaseMessages.getString(PKG, "System.Combo.Yes") + : BaseMessages.getString(PKG, "System.Combo.No")); + } + + wFields.setRowNums(); + wFields.optWidth(true); + + setActive(); + + wTransformName.selectAll(); + wTransformName.setFocus(); + } + + /** + * Stores the information from the dialog box in meta-data. + * + * @param meta + */ + private void getInfo( Plc4xReadMeta meta) throws HopException { + meta.setConnection(wConnection.getText()); + meta.setRowLimit(wLimit.getText()); + meta.setNeverEnding(wNeverEnding.getSelection()); + meta.setMaxwaitInMs(wMaxwait.getText()); + meta.setIntervalInMs(wInterval.getText()); + //meta.setRowTimeField(wRowTimeField.getText()); + //meta.setLastTimeField(wLastTimeField.getText()); + + meta.getFields().clear(); + + // CHECKSTYLE:Indentation:OFF + for (TableItem item : wFields.getNonEmptyItems()) { + Plc4xGeneratorField field = new Plc4xGeneratorField(); + field.setName(item.getText(1)); + field.setItem(item.getText(2)); + field.setFormat(item.getText(4)); + field.setLength(Const.toInt(item.getText(5), -1)); + field.setPrecision(Const.toInt(item.getText(6), -1)); + field.setCurrency(item.getText(7)); + field.setDecimal(item.getText(8)); + field.setGroup(item.getText(9)); + field.setValue(field.isSetEmptyString() ? "" : item.getText(10)); + field.setSetEmptyString( + BaseMessages.getString(PKG, "System.Combo.Yes").equalsIgnoreCase(item.getText(11))); + field.setType(field.isSetEmptyString() ? "String" : item.getText(3)); + + meta.getFields().add(field); + } + } + + /** + * Cancel the dialog. + */ + private void cancel() { + transformName = null; + input.setChanged( changed ); + dispose(); + } + + private void ok() { + if (Utils.isEmpty(wTransformName.getText())) { + return; + } + + transformName = wTransformName.getText(); // return value + try { + getInfo(new Plc4xReadMeta()); // to see if there is an exception + getInfo(input); // to put the content on the input structure for real if all is well. + dispose(); + } catch (HopException e) { + new ErrorDialog( + shell, + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title"), + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message"), + e); + } + } + + + /** + * Preview the data generated by this transform. This generates a pipeline using this transform & + * a dummy and previews it. + */ + private void preview() { + Plc4xReadMeta oneMeta = new Plc4xReadMeta(); + try { + getInfo(oneMeta); + } catch (HopException e) { + new ErrorDialog( + shell, + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title"), + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message"), + e); + return; + } + + PipelineMeta previewMeta = + PipelinePreviewFactory.generatePreviewPipeline( + pipelineMeta.getMetadataProvider(), oneMeta, wTransformName.getText()); + + EnterNumberDialog numberDialog = + new EnterNumberDialog( + shell, + props.getDefaultPreviewSize(), + BaseMessages.getString(PKG, "System.Dialog.EnterPreviewSize.Title"), + BaseMessages.getString(PKG, "System.Dialog.EnterPreviewSize.Message")); + int previewSize = numberDialog.open(); + if (previewSize > 0) { + PipelinePreviewProgressDialog progressDialog = + new PipelinePreviewProgressDialog( + shell, + variables, + previewMeta, + new String[] {wTransformName.getText()}, + new int[] {previewSize}); + progressDialog.open(); + + Pipeline pipeline = progressDialog.getPipeline(); + String loggingText = progressDialog.getLoggingText(); + + if (!progressDialog.isCancelled()) { + if (pipeline.getResult() != null && pipeline.getResult().getNrErrors() > 0) { + EnterTextDialog etd = + new EnterTextDialog( + shell, + BaseMessages.getString(PKG, "System.Dialog.PreviewError.Title"), + BaseMessages.getString(PKG, "System.Dialog.PreviewError.Message"), + loggingText, + true); + etd.setReadOnly(); + etd.open(); + } + } + + PreviewRowsDialog prd = + new PreviewRowsDialog( + shell, + variables, + SWT.NONE, + wTransformName.getText(), + progressDialog.getPreviewRowsMeta(wTransformName.getText()), + progressDialog.getPreviewRows(wTransformName.getText()), + loggingText); + prd.open(); + } + } + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadMeta.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadMeta.java new file mode 100644 index 00000000000..3946c9a310b --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadMeta.java @@ -0,0 +1,308 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xinput; + +import java.util.ArrayList; +import org.apache.hop.core.ICheckResult; +import org.apache.hop.core.annotations.Transform; +import org.apache.hop.core.exception.HopTransformException; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.metadata.api.IHopMetadataProvider; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.transform.BaseTransformMeta; +import org.apache.hop.pipeline.transform.ITransformMeta; +import org.apache.hop.pipeline.transform.TransformMeta; + +import java.util.List; +import org.apache.hop.core.Const; +import org.apache.hop.core.RowMetaAndData; +import org.apache.hop.core.row.IValueMeta; +import org.apache.hop.metadata.api.HopMetadataProperty; +import org.apache.hop.pipeline.transform.ITransformIOMeta; +import org.apache.hop.pipeline.transform.TransformIOMeta; +import org.apache.plc4x.hop.transforms.util.Plc4xGeneratorField; + +/** + * Meta data for the sample transform. + */ +@Transform( + id = "plc4x-read", + name = "i18n::Plc4x.Read.Name", + description = "i18n::Plc4x.Read.Description", + image = "plc4x_read.svg", + categoryDescription = "i18n:org.apache.plc4x.hop.transforms.plc4xinput:Plc4x.Category.plc4x", + documentationUrl = "https://plc4x.apache.org/users/integrations/apache-calcite.html" +) +public class Plc4xReadMeta extends BaseTransformMeta implements ITransformMeta { + + private static final Class PKG = Plc4xReadMeta.class; // Needed by Translator + + + @HopMetadataProperty( + key = "connection", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.Connection") + private String connection; + + @HopMetadataProperty( + key = "never_ending", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.NeverEnding") + private boolean neverEnding; + + @HopMetadataProperty( + key = "maxwait_in_ms", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.MaxwaitInMs") + private String maxwaitInMs; + + @HopMetadataProperty( + key = "interval_in_ms", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.IntervalInMs") + private String intervalInMs; + + @HopMetadataProperty( + key = "row_time_field", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.RowTimeField") + private String rowTimeField; + + @HopMetadataProperty( + key = "last_time_field", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.LastTimeField") + private String lastTimeField; + + @HopMetadataProperty( + key = "limit", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.RowLimit") + private String rowLimit; + + @HopMetadataProperty( + groupKey = "fields", + key = "field", + injectionGroupDescription = "Plc4x.Read.Meta.Injection.Fields", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.Fields") + private List fields; + + public Plc4xReadMeta() { + fields = new ArrayList<>(); + + rowLimit = "10"; + neverEnding = false; + maxwaitInMs = "1000"; + intervalInMs = "5000"; + rowTimeField = "now"; + lastTimeField = "last"; + } + + public Plc4xReadMeta(Plc4xReadMeta m) { + this.connection = m.connection; + this.neverEnding = m.neverEnding; + this.intervalInMs = m.intervalInMs; + this.rowTimeField = m.rowTimeField; + this.lastTimeField = m.lastTimeField; + this.rowLimit = m.rowLimit; + this.fields = new ArrayList<>(); + for (Plc4xGeneratorField field : m.fields) { + this.fields.add(new Plc4xGeneratorField(field)); + } + } + + @Override + public Plc4xReadMeta clone() { + return new Plc4xReadMeta(this); + } + + + + @Override + public void getFields( IRowMeta inputRowMeta, String name, IRowMeta[] info, TransformMeta nextTransform, + IVariables variables, IHopMetadataProvider metadataProvider ) throws HopTransformException { + try { + logBasic("PASO 1"); + List remarks = new ArrayList<>(); + RowMetaAndData rowMetaAndData = Plc4xRead.buildRow(this, remarks, name); + logBasic("PASO 2"); + if (!remarks.isEmpty()) { + logBasic("PASO 3"); + StringBuilder stringRemarks = new StringBuilder(); + for (ICheckResult remark : remarks) { + logBasic("PASO 3x: " + remark.toString()); + stringRemarks.append(remark.toString()).append(Const.CR); + } + logBasic("PASO 3.1"); + throw new HopTransformException(stringRemarks.toString()); + } + logBasic("PASO 4"); + for (IValueMeta valueMeta : rowMetaAndData.getRowMeta().getValueMetaList()) { + valueMeta.setOrigin(name); + } + logBasic("PASO 5"); + inputRowMeta.mergeRowMeta(rowMetaAndData.getRowMeta()); + } catch (Exception e) { + throw new HopTransformException(e); + } + } + + + public Plc4xRead createTransform(TransformMeta transformMeta, Plc4xReadData data, int copyNr, + PipelineMeta pipelineMeta, Pipeline pipeline ) { + return new Plc4xRead( transformMeta, this, data, copyNr, pipelineMeta, pipeline ); + } + + + public Plc4xReadData getTransformData() { + return new Plc4xReadData(); + } + +/* + @Override + public void loadXml( Node transformNode, IHopMetadataProvider metadataProvider ) throws HopXmlException { + //load the saved values from the transformnode + String sampleValue = XmlHandler.getTagValue( transformNode, "sampleValue" ); + + } +*/ + @Override + public void setDefault() { + //default values when creating a new transform + } + + + /** + * Returns the Input/Output metadata for this transform. + * The generator transform only produces output, does not accept input! + * TransformIOMeta(inputAcceptor, outputProducer, inputOptional, outputDynamic, inputDynamic) + */ + @Override + public ITransformIOMeta getTransformIOMeta() { + return new TransformIOMeta(false, true, false, false, false, false); + } + + /** + * Gets Plc4xConnection metadata name. + * + * @return value of intervalInMs + */ + public String getConnection() { + return connection; + } + + /** @param connection */ + public void setConnection(String connection) { + this.connection = connection; + } + + + /** + * Gets neverEnding + * + * @return value of neverEnding + */ + public boolean isNeverEnding() { + return neverEnding; + } + + /** @param neverEnding The neverEnding to set */ + public void setNeverEnding(boolean neverEnding) { + this.neverEnding = neverEnding; + } + + /** + * Gets intervalInMs + * + * @return value of intervalInMs + */ + public String getMaxwaitInMs() { + return maxwaitInMs; + } + + /** @param intervalInMs The intervalInMs to set */ + public void setMaxwaitInMs(String maxwaitInMs) { + this.maxwaitInMs = maxwaitInMs; + } + + /** + * Gets intervalInMs + * + * @return value of intervalInMs + */ + public String getIntervalInMs() { + return intervalInMs; + } + + /** @param intervalInMs The intervalInMs to set */ + public void setIntervalInMs(String intervalInMs) { + this.intervalInMs = intervalInMs; + } + + /** + * Gets rowTimeField + * + * @return value of rowTimeField + */ + public String getRowTimeField() { + return rowTimeField; + } + + /** @param rowTimeField The rowTimeField to set */ + public void setRowTimeField(String rowTimeField) { + this.rowTimeField = rowTimeField; + } + + /** + * Gets lastTimeField + * + * @return value of lastTimeField + */ + public String getLastTimeField() { + return lastTimeField; + } + + /** @param lastTimeField The lastTimeField to set */ + public void setLastTimeField(String lastTimeField) { + this.lastTimeField = lastTimeField; + } + + /** + * Gets rowLimit + * + * @return value of rowLimit + */ + public String getRowLimit() { + return rowLimit; + } + + /** @param rowLimit The rowLimit to set */ + public void setRowLimit(String rowLimit) { + this.rowLimit = rowLimit; + } + + /** + * Gets fields + * + * @return value of fields + */ + public List getFields() { + return fields; + } + + /** @param fields The fields to set */ + public void setFields(List fields) { + this.fields = fields; + } + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWrite.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWrite.java new file mode 100644 index 00000000000..2381564a755 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWrite.java @@ -0,0 +1,478 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xoutput; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; +import org.apache.commons.lang3.StringUtils; +import org.apache.hop.core.CheckResult; +import org.apache.hop.core.Const; +import org.apache.hop.core.ICheckResult; +import org.apache.hop.core.RowMetaAndData; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.exception.HopPluginException; +import org.apache.hop.core.exception.HopValueException; +import org.apache.hop.core.logging.LogLevel; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.row.IValueMeta; +import org.apache.hop.core.row.RowDataUtil; +import org.apache.hop.core.row.RowMeta; +import org.apache.hop.core.row.value.ValueMetaDate; +import org.apache.hop.core.row.value.ValueMetaFactory; +import org.apache.hop.core.util.StringUtil; +import org.apache.hop.core.util.Utils; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.metadata.api.IHopMetadataProvider; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.transform.BaseTransform; +import org.apache.hop.pipeline.transform.ITransform; +import org.apache.hop.pipeline.transform.TransformMeta; +import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.apache.plc4x.hop.transforms.util.Plc4xGeneratorField; +import org.apache.plc4x.hop.transforms.util.Plc4xPlcField; +import org.apache.plc4x.hop.transforms.util.Plc4xWrapperConnection; +import org.apache.plc4x.java.DefaultPlcDriverManager; +import org.apache.plc4x.java.api.PlcConnection; +import org.apache.plc4x.java.api.messages.PlcWriteRequest; +import org.apache.plc4x.java.api.messages.PlcWriteResponse; + +/** + * Transform That contains the basic skeleton needed to create your own plugin + * + */ +public class Plc4xWrite extends BaseTransform implements ITransform { + + private static final Class PKG = Plc4xWrite.class; // Needed by Translator + + private Plc4xConnection connmeta = null; + private Plc4xWrapperConnection connwrapper = null; + private PlcWriteRequest writeRequest = null; + private PlcWriteRequest.Builder builder = null; + private PlcWriteResponse writeResponse = null; + + private static final ReentrantLock lock = new ReentrantLock(); + + private static final String dummy = "dummy"; + + private Map index = new HashMap(); + private Map plcfields = new HashMap(); + + public Plc4xWrite(TransformMeta transformMeta, Plc4xWriteMeta meta, Plc4xWriteData data, int copyNr, PipelineMeta pipelineMeta, + Pipeline pipeline ) { + super( transformMeta, meta, data, copyNr, pipelineMeta, pipeline ); + } + + /* + * Including Date and Time field for every row + * + * @param meta Meta data from user dialog + * @param remarks Error registers + * @param origin transform instance name + */ + public static final RowMetaAndData buildRow( + Plc4xWriteMeta meta, List remarks, String origin) throws HopPluginException { + IRowMeta rowMeta = new RowMeta(); + Object[] rowData = RowDataUtil.allocateRowData(meta.getFields().size() + 2); + int index = 0; + + if (!Utils.isEmpty(meta.getRowTimeField())) { + rowMeta.addValueMeta(new ValueMetaDate(meta.getRowTimeField())); + rowData[index++] = null; + } + + if (!Utils.isEmpty(meta.getLastTimeField())) { + rowMeta.addValueMeta(new ValueMetaDate(meta.getLastTimeField())); + rowData[index++] = null; + } + + for (Plc4xGeneratorField field : meta.getFields()) { + int typeString = ValueMetaFactory.getIdForValueMeta(field.getType()); + if (StringUtils.isNotEmpty(field.getType())) { + System.out.println("typeString: " + typeString); + IValueMeta valueMeta = + ValueMetaFactory.createValueMeta(field.getName(), typeString); // build a + // value! + valueMeta.setLength(field.getLength()); + valueMeta.setPrecision(field.getPrecision()); + valueMeta.setConversionMask(field.getFormat()); + valueMeta.setCurrencySymbol(field.getCurrency()); + valueMeta.setGroupingSymbol(field.getGroup()); + valueMeta.setDecimalSymbol(field.getDecimal()); + valueMeta.setOrigin(origin); + + IValueMeta stringMeta = ValueMetaFactory.cloneValueMeta(valueMeta, IValueMeta.TYPE_STRING); + + if (field.isSetEmptyString()) { + // Set empty string + rowData[index] = StringUtil.EMPTY_STRING; + } else { + String stringValue = field.getValue(); + + // If the value is empty: consider it to be NULL. + if (Utils.isEmpty(stringValue)) { + rowData[index] = null; + + if (valueMeta.getType() == IValueMeta.TYPE_NONE) { + String message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.CheckResult.SpecifyTypeError", + valueMeta.getName(), + stringValue); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + } + } else { + // Convert the data from String to the specified type ... + // + try { + System.out.println("stringValue: " + stringValue); + rowData[index] = valueMeta.convertData(stringMeta, stringValue); + } catch (HopValueException e) { + switch (valueMeta.getType()) { + case IValueMeta.TYPE_NUMBER: + String message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.Number", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + case IValueMeta.TYPE_DATE: + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.Date", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + case IValueMeta.TYPE_INTEGER: + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.Integer", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + case IValueMeta.TYPE_BIGNUMBER: + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.BigNumber", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + case IValueMeta.TYPE_TIMESTAMP: + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.Timestamp", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + default: + // Boolean and binary don't throw errors normally, so it's probably an unspecified + // error problem... + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.CheckResult.SpecifyTypeError", + valueMeta.getName(), + stringValue); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + } + } + } + } + + // Now add value to the row! + // This is in fact a copy from the fields row, but now with data. + rowMeta.addValueMeta(valueMeta); + index++; + } + } + + return new RowMetaAndData(rowMeta, rowData); + } + + /* + * 1. Stores the indexes of the incoming fields from the user's selection. + * It is only done during the first cycle. + * 2. Block the other instances by means of a lock. + * 3. Try to locate an existing connection. + * 4. If it doesn't exist, it tries to take control of the routine to + * create an instance of PlcConnection and his wrapper. + * 5. Register the connection wrapper for global access. + * 6. If the connection to the PLC is made, then it creates the query + * and executes it. + * + */ + @Override + public boolean processRow() throws HopException { + final Object[] r = getRow(); // Get row from input rowset & set row busy! + + if (r == null) { + setOutputDone(); + return false; + } + + data.outputRowMeta = getInputRowMeta(); + + + if (first) { + index.clear(); + plcfields.clear(); + meta.getFields().forEach((f) ->{ + Integer i = getInputRowMeta().indexOfValue(f.getName()); //(01) + if (i>=0) { + index.put(f.getName(), i); + plcfields.put(f.getName(),Plc4xPlcField.of(f.getItem())); + } + }); + first = false; + } + + IRowMeta inputRowMeta = getInputRowMeta(); + + setLogLevel(LogLevel.DEBUG); + + if ((!meta.isNeverEnding() && data.rowsWritten >= data.rowLimit) && !isStopped()) { + setOutputDone(); // signal end to receiver(s) + return false; + } + + lock.lock(); //(01) + try { + IHopMetadataProvider metaprovider = getMetadataProvider(); + connmeta = metaprovider.getSerializer(Plc4xConnection.class).load(meta.getConnection()); + if (connwrapper == null) { + connwrapper = (Plc4xWrapperConnection) getPipeline().getExtensionDataMap().get(meta.getConnection()); //(02) + if (connwrapper != null) connwrapper.retain(); + }; + + if (connmeta == null){ + logError( + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.Log.SetMetadata", + meta.getConnection())); + } + + if ((connmeta != null) && (connwrapper == null)){ + writeRequest = null; + try{ + PlcConnection conn = new DefaultPlcDriverManager().getConnection(connmeta.getUrl()); //(03) + if (conn.isConnected()) { + connwrapper = new Plc4xWrapperConnection(conn); + getPipeline().getExtensionDataMap().put(meta.getConnection(), connwrapper); //(04) + } + } catch (Exception ex){ + setErrors(1L); + logError("Unable to create connection to PLC. " + ex.getMessage()); + } + } + } finally { + lock.unlock(); + } + + if ((connmeta != null) && (connwrapper != null)){ + if (connwrapper.getConnection().isConnected()){ + + builder = null; + builder = connwrapper.getConnection().writeRequestBuilder(); //(05) + Integer i; + for (Plc4xGeneratorField field: meta.getFields()){ + i = index.get(field.getName()); + if (i != null) { + //From Input Type + if (inputRowMeta.getValueMeta(i).getTypeDesc(). + equalsIgnoreCase(field.getType())) + switch(inputRowMeta.getValueMeta(i).getType()) { + case IValueMeta.TYPE_BOOLEAN: + case IValueMeta.TYPE_INTEGER: + case IValueMeta.TYPE_NUMBER: + case IValueMeta.TYPE_BIGNUMBER: + builder.addTagAddress(field.getName(), + field.getItem(), + r[i]); + break; + case IValueMeta.TYPE_DATE: + builder.addTagAddress(field.getName(), + field.getItem(), + Double.parseDouble(inputRowMeta.getString(r, i))); + break; + case IValueMeta.TYPE_TIMESTAMP: + builder.addTagAddress(field.getName(), + field.getItem(), + Double.parseDouble(inputRowMeta.getString(r, i))); + break; + case IValueMeta.TYPE_INET: + builder.addTagAddress(field.getName(), + field.getItem(), + Double.parseDouble(inputRowMeta.getString(r, i))); + break; + case IValueMeta.TYPE_STRING: + builder.addTagAddress(field.getName(), + field.getItem(), + Double.parseDouble(inputRowMeta.getString(r, i))); + break; + case IValueMeta.TYPE_SERIALIZABLE: + builder.addTagAddress(field.getName(), + field.getItem(), + Double.parseDouble(inputRowMeta.getString(r, i))); + break; + + } + //field.setValue(inputRowMeta.getString(r, i)); + }; + } + + writeRequest = builder.build(); + + try { + int maxwait = Integer.parseInt(meta.getMaxwaitInMs()); + maxwait = (maxwait<100)?100:maxwait; + writeResponse = writeRequest.execute().get(maxwait, TimeUnit.MILLISECONDS); + + index.forEach((n,y)->{ + System.out.println("Resultado: " + writeResponse.getResponseCode(n)); + }); + + } catch (Exception ex) { + setErrors(1L); + logError("Unable read from PLC. " + ex.getMessage()); + } + + } else { + setErrors(1L); + logError("PLC is not connected."); + setOutputDone(); + return false; + } + + } else { + setErrors(1L); + logError("PLC connection don't exist."); + setOutputDone(); + return false; + } + + + putRow(data.outputRowMeta, r); // return your data + data.rowsWritten++; + return true; + } + + + @Override + public boolean init() { + try { + if(super.init()){ + // Determine the number of rows to generate... + data.rowLimit = Const.toLong(resolve(meta.getRowLimit()), -1L); + data.rowsWritten = 0L; + data.delay = Const.toLong(resolve(meta.getIntervalInMs()), -1L); + + if (data.rowLimit < 0L) { // Unable to parse + logError(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Wrong.RowLimit.Number")); + return false; // fail + } + + // Create a row (constants) with all the values in it... + List remarks = new ArrayList<>(); // stores the errors... + RowMetaAndData outputRow = buildRow(meta, remarks, getTransformName()); + if (!remarks.isEmpty()) { + for (int i = 0; i < remarks.size(); i++) { + CheckResult cr = (CheckResult) remarks.get(i); + logError(cr.getText()); + } + return false; + } + + data.outputRowData = outputRow.getData(); + data.outputRowMeta = outputRow.getRowMeta(); + + return true; + } + return false; + } catch (Exception ex){ + setErrors(1L); + logError("Error initializing transform", ex); + return false; + } + } + + /* + * Here, must perform the cleaning of any resource, main of the connection to + * the associated PLC. + */ + @Override + public void cleanup() { + super.cleanup(); + logBasic("Cleanup. Release connection."); + if (connwrapper != null) + connwrapper.release(); + } + + + /* + * Here, must perform the cleaning of any resource. + * 1. Check if we have reference to wrapper. + * 2. Release de reference to object. + * 3. The lastone remove the global reference to connection wrapper. + * 4. Clear local references. + */ + @Override + public void dispose() { + super.dispose(); + if (connwrapper != null) { + logBasic("Dispose. Release connection: " + connwrapper.refCnt()); + connwrapper.release(); + if (!connwrapper.getConnection().isConnected()){ + getPipeline().getExtensionDataMap().remove(meta.getConnection()); + } + connwrapper = null; + writeRequest = null; + + } + } + + + + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteData.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteData.java new file mode 100644 index 00000000000..81f9c909b81 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteData.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xoutput; + +import org.apache.plc4x.hop.transforms.plc4xinput.*; +import java.util.Date; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.pipeline.transform.BaseTransformData; +import org.apache.hop.pipeline.transform.ITransformData; + + +public class Plc4xWriteData extends BaseTransformData implements ITransformData { + + //The Plc4xConnection metadata + public String connection; + + public IRowMeta outputRowMeta; + public Object[] outputRowData; + + public long rowLimit; + public long rowsWritten; + public Date rowDate; + public Date prevDate; + public long delay; + + + + /** + * Default constructor for SampleData. + */ + public Plc4xWriteData() { + super(); + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteDialog.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteDialog.java new file mode 100644 index 00000000000..1e2b3107ca5 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteDialog.java @@ -0,0 +1,674 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xoutput; + +import org.apache.plc4x.hop.transforms.plc4xinput.*; +import org.apache.hop.core.Const; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.row.value.ValueMetaFactory; +import org.apache.hop.core.util.Utils; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.PipelinePreviewFactory; +import org.apache.hop.pipeline.transform.BaseTransformMeta; +import org.apache.hop.pipeline.transform.ITransformDialog; +import org.apache.hop.ui.core.ConstUi; +import org.apache.hop.ui.core.dialog.BaseDialog; +import org.apache.hop.ui.core.dialog.EnterNumberDialog; +import org.apache.hop.ui.core.dialog.EnterTextDialog; +import org.apache.hop.ui.core.dialog.ErrorDialog; +import org.apache.hop.ui.core.dialog.PreviewRowsDialog; +import org.apache.hop.ui.core.widget.ColumnInfo; +import org.apache.hop.ui.core.widget.MetaSelectionLine; +import org.apache.hop.ui.core.widget.TableView; +import org.apache.hop.ui.core.widget.TextVar; +import org.apache.hop.ui.pipeline.dialog.PipelinePreviewProgressDialog; +import org.apache.hop.ui.pipeline.transform.BaseTransformDialog; +import org.apache.hop.ui.pipeline.transform.ITableItemInsertListener; +import org.apache.hop.ui.util.SwtSvgImageUtil; +import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.apache.plc4x.hop.transforms.util.Plc4xGeneratorField; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.*; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; + +public class Plc4xWriteDialog extends BaseTransformDialog implements ITransformDialog { + private static final Class PKG = Plc4xWriteDialog.class; // Needed by Translator + + private MetaSelectionLine wConnection; + + private Label wlLimit; + private TextVar wLimit; + + private Button wNeverEnding; + + private Label wlMaxwait; + private TextVar wMaxwait; + + private Label wlInterval; + private TextVar wInterval; + + private Label wlRowTimeField; + private TextVar wRowTimeField; + + private Label wlLastTimeField; + private TextVar wLastTimeField; + + private TableView wFields; + + private Button wGetPrvFields; + + private final Plc4xWriteMeta input; + + public Plc4xWriteDialog(Shell parent, IVariables variables , Object in, PipelineMeta pipelineMeta, String sname ) { + super( parent, variables, (BaseTransformMeta) in, pipelineMeta, sname ); + input = (Plc4xWriteMeta) in; + } + + @Override + public String open() { + Shell parent = getParent(); + + shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX | SWT.MIN); + props.setLook(shell); + setShellImage(shell, input); + + ModifyListener lsMod = e -> input.setChanged(); + changed = input.hasChanged(); + + FormLayout formLayout = new FormLayout(); + formLayout.marginWidth = Const.FORM_MARGIN; + formLayout.marginHeight = Const.FORM_MARGIN; + + shell.setLayout(formLayout); + shell.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.DialogTitle")); + + int middle = props.getMiddlePct(); + int margin = props.getMargin(); + + // Filename line + wlTransformName = new Label(shell, SWT.RIGHT); + wlTransformName.setText(BaseMessages.getString(PKG, "System.Label.TransformName")); + props.setLook(wlTransformName); + fdlTransformName = new FormData(); + fdlTransformName.left = new FormAttachment(0, 0); + fdlTransformName.right = new FormAttachment(middle, -margin); + fdlTransformName.top = new FormAttachment(0, margin); + wlTransformName.setLayoutData(fdlTransformName); + + wTransformName = new Text(shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + wTransformName.setText(transformName); + props.setLook(wTransformName); + wTransformName.addModifyListener(lsMod); + fdTransformName = new FormData(); + fdTransformName.left = new FormAttachment(middle, 0); + fdTransformName.top = new FormAttachment(0, margin); + fdTransformName.right = new FormAttachment(100, 0); + wTransformName.setLayoutData(fdTransformName); + + // Connection line + wConnection = + new MetaSelectionLine<>( + variables, + metadataProvider, + Plc4xConnection.class, + shell, + SWT.NONE, + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Connection.Label"), + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Connection.Tooltip")); + FormData fdConnection = new FormData(); + fdConnection.left = new FormAttachment(0, 0); + fdConnection.right = new FormAttachment(100, 0); + fdConnection.top = new FormAttachment(wTransformName, margin); + wConnection.setLayoutData(fdConnection); + props.setLook(wConnection); + try { + wConnection.fillItems(); + } catch (Exception e) { + new ErrorDialog(shell, "Error", "Error listing Cassandra connection metadata objects", e); + } + + Control lastControl = wConnection; + + wlLimit = new Label(shell, SWT.RIGHT); + wlLimit.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Limit.Label")); + props.setLook(wlLimit); + FormData fdlLimit = new FormData(); + fdlLimit.left = new FormAttachment(0, 0); + fdlLimit.right = new FormAttachment(middle, -margin); + fdlLimit.top = new FormAttachment(lastControl, margin); + wlLimit.setLayoutData(fdlLimit); + wLimit = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wLimit); + wLimit.addModifyListener(lsMod); + FormData fdLimit = new FormData(); + fdLimit.left = new FormAttachment(middle, 0); + fdLimit.top = new FormAttachment(lastControl, margin); + fdLimit.right = new FormAttachment(100, 0); + wLimit.setLayoutData(fdLimit); + lastControl = wLimit; + + Label wlNeverEnding = new Label(shell, SWT.RIGHT); + wlNeverEnding.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.NeverEnding.Label")); + props.setLook(wlNeverEnding); + FormData fdlNeverEnding = new FormData(); + fdlNeverEnding.left = new FormAttachment(0, 0); + fdlNeverEnding.right = new FormAttachment(middle, -margin); + fdlNeverEnding.top = new FormAttachment(lastControl, margin); + wlNeverEnding.setLayoutData(fdlNeverEnding); + wNeverEnding = new Button(shell, SWT.CHECK); + props.setLook(wNeverEnding); + wNeverEnding.addSelectionListener( + new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + setActive(); + input.setChanged(); + } + }); + FormData fdNeverEnding = new FormData(); + fdNeverEnding.left = new FormAttachment(middle, 0); + fdNeverEnding.top = new FormAttachment(wlNeverEnding, 0, SWT.CENTER); + fdNeverEnding.right = new FormAttachment(100, 0); + wNeverEnding.setLayoutData(fdNeverEnding); + lastControl = wlNeverEnding; + + wlMaxwait = new Label(shell, SWT.RIGHT); + wlMaxwait.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Maxwait.Label")); + props.setLook(wlMaxwait); + FormData fdlMaxwait = new FormData(); + fdlMaxwait.left = new FormAttachment(0, 0); + fdlMaxwait.right = new FormAttachment(middle, -margin); + fdlMaxwait.top = new FormAttachment(lastControl, margin); + wlMaxwait.setLayoutData(fdlMaxwait); + wMaxwait = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wMaxwait); + wMaxwait.addModifyListener(lsMod); + FormData fdMaxwait = new FormData(); + fdMaxwait.left = new FormAttachment(middle, 0); + fdMaxwait.top = new FormAttachment(lastControl, margin); + fdMaxwait.right = new FormAttachment(100, 0); + wMaxwait.setLayoutData(fdMaxwait); + lastControl = wMaxwait; + + wlInterval = new Label(shell, SWT.RIGHT); + wlInterval.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Interval.Label")); + props.setLook(wlInterval); + FormData fdlInterval = new FormData(); + fdlInterval.left = new FormAttachment(0, 0); + fdlInterval.right = new FormAttachment(middle, -margin); + fdlInterval.top = new FormAttachment(lastControl, margin); + wlInterval.setLayoutData(fdlInterval); + wInterval = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wInterval); + wInterval.addModifyListener(lsMod); + FormData fdInterval = new FormData(); + fdInterval.left = new FormAttachment(middle, 0); + fdInterval.top = new FormAttachment(lastControl, margin); + fdInterval.right = new FormAttachment(100, 0); + wInterval.setLayoutData(fdInterval); + lastControl = wInterval; + + /* + wlRowTimeField = new Label(shell, SWT.RIGHT); + wlRowTimeField.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.RowTimeField.Label")); + props.setLook(wlRowTimeField); + FormData fdlRowTimeField = new FormData(); + fdlRowTimeField.left = new FormAttachment(0, 0); + fdlRowTimeField.right = new FormAttachment(middle, -margin); + fdlRowTimeField.top = new FormAttachment(lastControl, margin); + wlRowTimeField.setLayoutData(fdlRowTimeField); + wRowTimeField = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wRowTimeField); + wRowTimeField.addModifyListener(lsMod); + FormData fdRowTimeField = new FormData(); + fdRowTimeField.left = new FormAttachment(middle, 0); + fdRowTimeField.top = new FormAttachment(lastControl, margin); + fdRowTimeField.right = new FormAttachment(100, 0); + wRowTimeField.setLayoutData(fdRowTimeField); + lastControl = wRowTimeField; + + wlLastTimeField = new Label(shell, SWT.RIGHT); + wlLastTimeField.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.LastTimeField.Label")); + props.setLook(wlLastTimeField); + FormData fdlLastTimeField = new FormData(); + fdlLastTimeField.left = new FormAttachment(0, 0); + fdlLastTimeField.right = new FormAttachment(middle, -margin); + fdlLastTimeField.top = new FormAttachment(lastControl, margin); + wlLastTimeField.setLayoutData(fdlLastTimeField); + wLastTimeField = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wLastTimeField); + wLastTimeField.addModifyListener(lsMod); + FormData fdLastTimeField = new FormData(); + fdLastTimeField.left = new FormAttachment(middle, 0); + fdLastTimeField.top = new FormAttachment(lastControl, margin); + fdLastTimeField.right = new FormAttachment(100, 0); + wLastTimeField.setLayoutData(fdLastTimeField); + lastControl = wLastTimeField; + */ + wOk = new Button(shell, SWT.PUSH); + wOk.setText(BaseMessages.getString(PKG, "System.Button.OK")); + wOk.addListener(SWT.Selection, e -> ok()); + + wGet = new Button(shell, SWT.PUSH); + wGet.setText(BaseMessages.getString(PKG, "Get Fields")); + wGet.addListener(SWT.Selection, e -> getfields()); + + wPreview = new Button(shell, SWT.PUSH); + wPreview.setText(BaseMessages.getString(PKG, "System.Button.Preview")); + wPreview.addListener(SWT.Selection, e -> preview()); + + wCancel = new Button(shell, SWT.PUSH); + wCancel.setText(BaseMessages.getString(PKG, "System.Button.Cancel")); + wCancel.addListener(SWT.Selection, e -> cancel()); + + setButtonPositions(new Button[] {wOk, wPreview, wGet, wCancel}, margin, null); + + Label wlFields = new Label(shell, SWT.NONE); + wlFields.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Fields.Label")); + props.setLook(wlFields); + FormData fdlFields = new FormData(); + fdlFields.left = new FormAttachment(0, 0); + fdlFields.top = new FormAttachment(lastControl, margin); + wlFields.setLayoutData(fdlFields); + lastControl = wlFields; + + final int nrFields = input.getFields().size(); + + ColumnInfo[] colinf = + new ColumnInfo[] { + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Name"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Fields.Item"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Type"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + ValueMetaFactory.getValueMetaNames()), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Format"), + ColumnInfo.COLUMN_TYPE_FORMAT, + 2), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Length"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Precision"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Currency"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Decimal"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Group"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Value"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.SetEmptyString"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + new String[] { + BaseMessages.getString(PKG, "System.Combo.Yes"), + BaseMessages.getString(PKG, "System.Combo.No") + }) + }; + + wFields = + new TableView( + variables, + shell, + SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI, + colinf, + nrFields, + lsMod, + props); + + FormData fdFields = new FormData(); + fdFields.left = new FormAttachment(0, 0); + fdFields.top = new FormAttachment(lastControl, margin); + fdFields.right = new FormAttachment(100, 0); + fdFields.bottom = new FormAttachment(wOk, -2 * margin); + wFields.setLayoutData(fdFields); + + lsResize = + event -> { + Point size = shell.getSize(); + wFields.setSize(size.x - 10, size.y - 50); + wFields.table.setSize(size.x - 10, size.y - 50); + wFields.redraw(); + }; + shell.addListener(SWT.Resize, lsResize); + + getData(); + input.setChanged(changed); + + BaseDialog.defaultShellHandling(shell, c -> ok(), c -> cancel()); + + return transformName; + }; + + public void setActive() { + boolean neverEnding = wNeverEnding.getSelection(); + + wlLimit.setEnabled(!neverEnding); + wLimit.setEnabled(!neverEnding); + + //wlInterval.setEnabled(neverEnding); + //wInterval.setEnabled(neverEnding); + + //wlRowTimeField.setEnabled(neverEnding); + //wRowTimeField.setEnabled(neverEnding); + + //wlLastTimeField.setEnabled(neverEnding); + //wLastTimeField.setEnabled(neverEnding); + } + + + + private Image getImage() { + return SwtSvgImageUtil.getImage( shell.getDisplay(), getClass().getClassLoader(), "plc4x_toddy_read.svg", ConstUi.LARGE_ICON_SIZE, + ConstUi.LARGE_ICON_SIZE ); + } + + /** + * Copy information from the meta-data input to the dialog fields. + * + */ + public void getData() { + if (isDebug()) { + logDebug("getting fields info..."); + } + if (input.getConnection() == null) { + wConnection.setText(""); + } else { + wConnection.setText(input.getConnection()); + } + + wLimit.setText(input.getRowLimit()); + wNeverEnding.setSelection(input.isNeverEnding()); + wMaxwait.setText(Const.NVL(input.getMaxwaitInMs(), "")); + wInterval.setText(Const.NVL(input.getIntervalInMs(), "")); + // wRowTimeField.setText(Const.NVL(input.getRowTimeField(), "")); + //wLastTimeField.setText(Const.NVL(input.getLastTimeField(), "")); + + for (int i = 0; i < input.getFields().size(); i++) { + Plc4xGeneratorField field = input.getFields().get(i); + TableItem item = wFields.table.getItem(i); + int col = 1; + item.setText(col++, Const.NVL(field.getName(), "")); + + item.setText(col++, Const.NVL(field.getItem(), "")); + + String type = field.getType(); + String format = field.getFormat(); + String length = field.getLength() < 0 ? "" : ("" + field.getLength()); + String prec = field.getPrecision() < 0 ? "" : ("" + field.getPrecision()); + + String curr = field.getCurrency(); + String group = field.getGroup(); + String decim = field.getDecimal(); + String def = field.getValue(); + + item.setText(col++, Const.NVL(type, "")); + item.setText(col++, Const.NVL(format, "")); + item.setText(col++, Const.NVL(length, "")); + item.setText(col++, Const.NVL(prec, "")); + item.setText(col++, Const.NVL(curr, "")); + item.setText(col++, Const.NVL(decim, "")); + item.setText(col++, Const.NVL(group, "")); + item.setText(col++, Const.NVL(def, "")); + item.setText( + col++, + field.isSetEmptyString() + ? BaseMessages.getString(PKG, "System.Combo.Yes") + : BaseMessages.getString(PKG, "System.Combo.No")); + } + + wFields.setRowNums(); + wFields.optWidth(true); + + setActive(); + + wTransformName.selectAll(); + wTransformName.setFocus(); + } + + /** + * Stores the information from the dialog box in meta-data. + * + * @param meta + */ + private void getInfo( Plc4xWriteMeta meta) throws HopException { + meta.setConnection(wConnection.getText()); + meta.setRowLimit(wLimit.getText()); + meta.setNeverEnding(wNeverEnding.getSelection()); + meta.setMaxwaitInMs(wMaxwait.getText()); + meta.setIntervalInMs(wInterval.getText()); + //meta.setRowTimeField(wRowTimeField.getText()); + //meta.setLastTimeField(wLastTimeField.getText()); + + meta.getFields().clear(); + + // CHECKSTYLE:Indentation:OFF + for (TableItem item : wFields.getNonEmptyItems()) { + Plc4xGeneratorField field = new Plc4xGeneratorField(); + field.setName(item.getText(1)); + field.setItem(item.getText(2)); + field.setFormat(item.getText(4)); + field.setLength(Const.toInt(item.getText(5), -1)); + field.setPrecision(Const.toInt(item.getText(6), -1)); + field.setCurrency(item.getText(7)); + field.setDecimal(item.getText(8)); + field.setGroup(item.getText(9)); + field.setValue(field.isSetEmptyString() ? "" : item.getText(10)); + field.setSetEmptyString( + BaseMessages.getString(PKG, "System.Combo.Yes").equalsIgnoreCase(item.getText(11))); + field.setType(field.isSetEmptyString() ? "String" : item.getText(3)); + + meta.getFields().add(field); + } + } + + /** + * Get previos transform fields. + * Clear all information in actual fields. + * + * @param meta + */ + private void getPrevFields(Plc4xWriteMeta meta) throws HopException { + IRowMeta r = pipelineMeta.getPrevTransformFields(variables, transformMeta); + if (r != null){ + meta.getFields().clear(); + r.getValueMetaList().forEach((f)->{ + Plc4xGeneratorField field = new Plc4xGeneratorField(); + field.setName(f.getName()); + field.setItem(""); + field.setType(f.getTypeDesc()); + field.setFormat(f.getFormatMask()); + field.setLength(f.getLength()); + field.setPrecision(f.getPrecision()); + field.setCurrency(f.getCurrencySymbol()); + field.setDecimal(f.getDecimalSymbol()); + field.setGroup(f.getGroupingSymbol()); + field.setValue(f.getStringEncoding()); + meta.getFields().add(field); + }); + } + } + + + /** + * Cancel the dialog. + */ + private void cancel() { + transformName = null; + input.setChanged( changed ); + dispose(); + } + + private void ok() { + if (Utils.isEmpty(wTransformName.getText())) { + return; + } + + transformName = wTransformName.getText(); // return value + try { + getInfo(new Plc4xWriteMeta()); // to see if there is an exception + getInfo(input); // to put the content on the input structure for real if all is well. + dispose(); + } catch (HopException e) { + new ErrorDialog( + shell, + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title"), + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message"), + e); + } + } + +private void getfields() { + try { + + IRowMeta r = pipelineMeta.getPrevTransformFields(variables, transformName); + + if (r != null && !r.isEmpty()) { + ITableItemInsertListener listener = + (tableItem, v) -> { + + tableItem.setText(2, ""); + tableItem.setText(3, v.getTypeDesc()); + tableItem.setText(4, v.getFormatMask()==null?"":v.getFormatMask()); + tableItem.setText(5, Integer.toString(v.getLength())); + tableItem.setText(6, Integer.toString(v.getPrecision())); + tableItem.setText(7, v.getCurrencySymbol()==null?"":v.getCurrencySymbol()); + tableItem.setText(8, v.getDecimalSymbol()==null?"":v.getDecimalSymbol()); + tableItem.setText(9, v.getGroupingSymbol()==null?"":v.getGroupingSymbol()); + //tableItem.setText(10, "N"); + tableItem.setText(11, "N"); + return true; + }; + BaseTransformDialog.getFieldsFromPrevious( + r, wFields, 1, new int[] {1}, null, -1, -1, listener); + } + + + + + } catch (Exception ex){ + new ErrorDialog( + shell, + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title"), + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message"), + ex); + } +} + + /** + * Preview the data generated by this transform. This generates a pipeline using this transform & + * a dummy and previews it. + */ + private void preview() { + Plc4xWriteMeta oneMeta = new Plc4xWriteMeta(); + try { + getInfo(oneMeta); + } catch (HopException e) { + new ErrorDialog( + shell, + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title"), + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message"), + e); + return; + } + + PipelineMeta previewMeta = + PipelinePreviewFactory.generatePreviewPipeline( + pipelineMeta.getMetadataProvider(), oneMeta, wTransformName.getText()); + + EnterNumberDialog numberDialog = + new EnterNumberDialog( + shell, + props.getDefaultPreviewSize(), + BaseMessages.getString(PKG, "System.Dialog.EnterPreviewSize.Title"), + BaseMessages.getString(PKG, "System.Dialog.EnterPreviewSize.Message")); + int previewSize = numberDialog.open(); + if (previewSize > 0) { + PipelinePreviewProgressDialog progressDialog = + new PipelinePreviewProgressDialog( + shell, + variables, + previewMeta, + new String[] {wTransformName.getText()}, + new int[] {previewSize}); + progressDialog.open(); + + Pipeline pipeline = progressDialog.getPipeline(); + String loggingText = progressDialog.getLoggingText(); + + if (!progressDialog.isCancelled()) { + if (pipeline.getResult() != null && pipeline.getResult().getNrErrors() > 0) { + EnterTextDialog etd = + new EnterTextDialog( + shell, + BaseMessages.getString(PKG, "System.Dialog.PreviewError.Title"), + BaseMessages.getString(PKG, "System.Dialog.PreviewError.Message"), + loggingText, + true); + etd.setReadOnly(); + etd.open(); + } + } + + PreviewRowsDialog prd = + new PreviewRowsDialog( + shell, + variables, + SWT.NONE, + wTransformName.getText(), + progressDialog.getPreviewRowsMeta(wTransformName.getText()), + progressDialog.getPreviewRows(wTransformName.getText()), + loggingText); + prd.open(); + } + } + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteMeta.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteMeta.java new file mode 100644 index 00000000000..d3996ad4a93 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteMeta.java @@ -0,0 +1,310 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xoutput; + +import org.apache.plc4x.hop.transforms.plc4xinput.*; +import java.util.ArrayList; +import org.apache.hop.core.ICheckResult; +import org.apache.hop.core.annotations.Transform; +import org.apache.hop.core.exception.HopTransformException; +import org.apache.hop.core.exception.HopXmlException; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.core.xml.XmlHandler; +import org.apache.hop.metadata.api.IHopMetadataProvider; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.transform.BaseTransformMeta; +import org.apache.hop.pipeline.transform.ITransformMeta; +import org.apache.hop.pipeline.transform.TransformMeta; +import org.w3c.dom.Node; + +import java.util.List; +import org.apache.hop.core.Const; +import org.apache.hop.core.RowMetaAndData; +import org.apache.hop.core.row.IValueMeta; +import org.apache.hop.metadata.api.HopMetadataProperty; +import org.apache.hop.pipeline.transform.ITransformIOMeta; +import org.apache.hop.pipeline.transform.TransformIOMeta; +import org.apache.plc4x.hop.transforms.util.Plc4xGeneratorField; + +/** + * Meta data for the sample transform. + */ +@Transform( + id = "plc4x-write", + name = "i18n::Plc4x.Read.Name", + description = "i18n::Plc4x.Read.Description", + image = "plc4x_write.svg", + categoryDescription = "i18n:org.apache.plc4x.hop.transforms.plc4xoutput:Plc4x.Category.plc4x", + documentationUrl = "https://plc4x.apache.org/users/integrations/apache-calcite.html" +) +public class Plc4xWriteMeta extends BaseTransformMeta implements ITransformMeta { + + private static final Class PKG = Plc4xWriteMeta.class; // Needed by Translator + + + @HopMetadataProperty( + key = "connection", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.Connection") + private String connection; + + @HopMetadataProperty( + key = "never_ending", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.NeverEnding") + private boolean neverEnding; + + @HopMetadataProperty( + key = "maxwait_in_ms", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.MaxwaitInMs") + private String maxwaitInMs; + + @HopMetadataProperty( + key = "interval_in_ms", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.IntervalInMs") + private String intervalInMs; + + @HopMetadataProperty( + key = "row_time_field", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.RowTimeField") + private String rowTimeField; + + @HopMetadataProperty( + key = "last_time_field", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.LastTimeField") + private String lastTimeField; + + @HopMetadataProperty( + key = "limit", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.RowLimit") + private String rowLimit; + + @HopMetadataProperty( + groupKey = "fields", + key = "field", + injectionGroupDescription = "Plc4x.Read.Meta.Injection.Fields", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.Fields") + private List fields; + + public Plc4xWriteMeta() { + fields = new ArrayList<>(); + + rowLimit = "10"; + neverEnding = false; + maxwaitInMs = "1000"; + intervalInMs = "5000"; + rowTimeField = "now"; + lastTimeField = "last"; + } + + public Plc4xWriteMeta(Plc4xWriteMeta m) { + this.connection = m.connection; + this.neverEnding = m.neverEnding; + this.intervalInMs = m.intervalInMs; + this.rowTimeField = m.rowTimeField; + this.lastTimeField = m.lastTimeField; + this.rowLimit = m.rowLimit; + this.fields = new ArrayList<>(); + for (Plc4xGeneratorField field : m.fields) { + this.fields.add(new Plc4xGeneratorField(field)); + } + } + + @Override + public Plc4xWriteMeta clone() { + return new Plc4xWriteMeta(this); + } + + + + @Override + public void getFields( IRowMeta inputRowMeta, String name, IRowMeta[] info, TransformMeta nextTransform, + IVariables variables, IHopMetadataProvider metadataProvider ) throws HopTransformException { + try { + logBasic("PASO 1"); + List remarks = new ArrayList<>(); + RowMetaAndData rowMetaAndData = Plc4xWrite.buildRow(this, remarks, name); + logBasic("PASO 2"); + if (!remarks.isEmpty()) { + logBasic("PASO 3"); + StringBuilder stringRemarks = new StringBuilder(); + for (ICheckResult remark : remarks) { + logBasic("PASO 3x: " + remark.toString()); + stringRemarks.append(remark.toString()).append(Const.CR); + } + logBasic("PASO 3.1"); + throw new HopTransformException(stringRemarks.toString()); + } + logBasic("PASO 4"); + for (IValueMeta valueMeta : rowMetaAndData.getRowMeta().getValueMetaList()) { + valueMeta.setOrigin(name); + } + logBasic("PASO 5"); + inputRowMeta.mergeRowMeta(rowMetaAndData.getRowMeta()); + } catch (Exception e) { + throw new HopTransformException(e); + } + } + + + public Plc4xWrite createTransform(TransformMeta transformMeta, Plc4xWriteData data, int copyNr, + PipelineMeta pipelineMeta, Pipeline pipeline ) { + return new Plc4xWrite( transformMeta, this, data, copyNr, pipelineMeta, pipeline ); + } + + public Plc4xWriteData getTransformData() { + return new Plc4xWriteData(); + } +/* + @Override + public void loadXml( Node transformNode, IHopMetadataProvider metadataProvider ) throws HopXmlException { + //load the saved values from the transformnode + String sampleValue = XmlHandler.getTagValue( transformNode, "sampleValue" ); + + } +*/ + @Override + public void setDefault() { + //default values when creating a new transform + } + + + /** + * Returns the Input/Output metadata for this transform. + * The generator transform only produces output, does not accept input! + * TransformIOMeta(inputAcceptor, outputProducer, inputOptional, outputDynamic, inputDynamic) + */ + @Override + public ITransformIOMeta getTransformIOMeta() { + return new TransformIOMeta(false, true, false, false, false, false); + } + + /** + * Gets Plc4xConnection metadata name. + * + * @return value of intervalInMs + */ + public String getConnection() { + return connection; + } + + /** @param connection */ + public void setConnection(String connection) { + this.connection = connection; + } + + + /** + * Gets neverEnding + * + * @return value of neverEnding + */ + public boolean isNeverEnding() { + return neverEnding; + } + + /** @param neverEnding The neverEnding to set */ + public void setNeverEnding(boolean neverEnding) { + this.neverEnding = neverEnding; + } + + /** + * Gets intervalInMs + * + * @return value of intervalInMs + */ + public String getMaxwaitInMs() { + return maxwaitInMs; + } + + /** @param intervalInMs The intervalInMs to set */ + public void setMaxwaitInMs(String maxwaitInMs) { + this.maxwaitInMs = maxwaitInMs; + } + + /** + * Gets intervalInMs + * + * @return value of intervalInMs + */ + public String getIntervalInMs() { + return intervalInMs; + } + + /** @param intervalInMs The intervalInMs to set */ + public void setIntervalInMs(String intervalInMs) { + this.intervalInMs = intervalInMs; + } + + /** + * Gets rowTimeField + * + * @return value of rowTimeField + */ + public String getRowTimeField() { + return rowTimeField; + } + + /** @param rowTimeField The rowTimeField to set */ + public void setRowTimeField(String rowTimeField) { + this.rowTimeField = rowTimeField; + } + + /** + * Gets lastTimeField + * + * @return value of lastTimeField + */ + public String getLastTimeField() { + return lastTimeField; + } + + /** @param lastTimeField The lastTimeField to set */ + public void setLastTimeField(String lastTimeField) { + this.lastTimeField = lastTimeField; + } + + /** + * Gets rowLimit + * + * @return value of rowLimit + */ + public String getRowLimit() { + return rowLimit; + } + + /** @param rowLimit The rowLimit to set */ + public void setRowLimit(String rowLimit) { + this.rowLimit = rowLimit; + } + + /** + * Gets fields + * + * @return value of fields + */ + public List getFields() { + return fields; + } + + /** @param fields The fields to set */ + public void setFields(List fields) { + this.fields = fields; + } + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubs.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubs.java new file mode 100644 index 00000000000..51c6c9d5366 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubs.java @@ -0,0 +1,446 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xsubs; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; +import org.apache.commons.lang3.StringUtils; +import org.apache.hop.core.CheckResult; +import org.apache.hop.core.Const; +import org.apache.hop.core.ICheckResult; +import org.apache.hop.core.RowMetaAndData; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.exception.HopPluginException; +import org.apache.hop.core.exception.HopValueException; +import org.apache.hop.core.logging.LogLevel; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.row.IValueMeta; +import org.apache.hop.core.row.RowDataUtil; +import org.apache.hop.core.row.RowMeta; +import org.apache.hop.core.row.value.ValueMetaDate; +import org.apache.hop.core.row.value.ValueMetaFactory; +import org.apache.hop.core.util.StringUtil; +import org.apache.hop.core.util.Utils; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.metadata.api.IHopMetadataProvider; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.transform.BaseTransform; +import org.apache.hop.pipeline.transform.ITransform; +import org.apache.hop.pipeline.transform.TransformMeta; +import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.apache.plc4x.hop.transforms.util.Plc4xGeneratorField; +import org.apache.plc4x.hop.transforms.util.Plc4xPlcField; +import org.apache.plc4x.hop.transforms.util.Plc4xWrapperConnection; +import org.apache.plc4x.java.DefaultPlcDriverManager; +import org.apache.plc4x.java.api.PlcConnection; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.messages.PlcReadResponse; + +/** + * Transform That contains the basic skeleton needed to create your own plugin + * + */ +public class Plc4xSubs extends BaseTransform implements ITransform { + + private static final Class PKG = Plc4xSubs.class; // Needed by Translator + + private Plc4xConnection connmeta = null; + private Plc4xWrapperConnection connwrapper = null; + private PlcReadRequest readRequest = null; + private PlcReadResponse readResponse = null; + private int maxwait = 0; + private static final ReentrantLock lock = new ReentrantLock(); + + private static final String dummy = "dummy"; + + private Map index = new HashMap(); + private Map plcfields = new HashMap(); + + public Plc4xSubs(TransformMeta transformMeta, Plc4xSubsMeta meta, Plc4xSubsData data, int copyNr, PipelineMeta pipelineMeta, + Pipeline pipeline ) { + super( transformMeta, meta, data, copyNr, pipelineMeta, pipeline ); + } + + /* + * Including Date and Time field for every row + * + * @param meta Meta data from user dialog + * @param remarks Error registers + * @param origin transform instance name + */ + public static final RowMetaAndData buildRow( + Plc4xSubsMeta meta, List remarks, String origin) throws HopPluginException { + IRowMeta rowMeta = new RowMeta(); + Object[] rowData = RowDataUtil.allocateRowData(meta.getFields().size() + 2); + int index = 0; + + if (!Utils.isEmpty(meta.getRowTimeField())) { + rowMeta.addValueMeta(new ValueMetaDate(meta.getRowTimeField())); + rowData[index++] = null; + } + + if (!Utils.isEmpty(meta.getLastTimeField())) { + rowMeta.addValueMeta(new ValueMetaDate(meta.getLastTimeField())); + rowData[index++] = null; + } + + for (Plc4xGeneratorField field : meta.getFields()) { + int typeString = ValueMetaFactory.getIdForValueMeta(field.getType()); + if (StringUtils.isNotEmpty(field.getType())) { + System.out.println("typeString: " + typeString); + IValueMeta valueMeta = + ValueMetaFactory.createValueMeta(field.getName(), typeString); // build a + // value! + valueMeta.setLength(field.getLength()); + valueMeta.setPrecision(field.getPrecision()); + valueMeta.setConversionMask(field.getFormat()); + valueMeta.setCurrencySymbol(field.getCurrency()); + valueMeta.setGroupingSymbol(field.getGroup()); + valueMeta.setDecimalSymbol(field.getDecimal()); + valueMeta.setOrigin(origin); + + IValueMeta stringMeta = ValueMetaFactory.cloneValueMeta(valueMeta, IValueMeta.TYPE_STRING); + + if (field.isSetEmptyString()) { + // Set empty string + rowData[index] = StringUtil.EMPTY_STRING; + } else { + String stringValue = field.getValue(); + + // If the value is empty: consider it to be NULL. + if (Utils.isEmpty(stringValue)) { + rowData[index] = null; + + if (valueMeta.getType() == IValueMeta.TYPE_NONE) { + String message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.CheckResult.SpecifyTypeError", + valueMeta.getName(), + stringValue); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + } + } else { + // Convert the data from String to the specified type ... + // + try { + System.out.println("stringValue: " + stringValue); + rowData[index] = valueMeta.convertData(stringMeta, stringValue); + } catch (HopValueException e) { + switch (valueMeta.getType()) { + case IValueMeta.TYPE_NUMBER: + String message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.Number", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + case IValueMeta.TYPE_DATE: + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.Date", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + case IValueMeta.TYPE_INTEGER: + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.Integer", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + case IValueMeta.TYPE_BIGNUMBER: + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.BigNumber", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + case IValueMeta.TYPE_TIMESTAMP: + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.BuildRow.Error.Parsing.Timestamp", + valueMeta.getName(), + stringValue, + e.toString()); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + + default: + // Boolean and binary don't throw errors normally, so it's probably an unspecified + // error problem... + message = + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.CheckResult.SpecifyTypeError", + valueMeta.getName(), + stringValue); + remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null)); + break; + } + } + } + } + + // Now add value to the row! + // This is in fact a copy from the fields row, but now with data. + rowMeta.addValueMeta(valueMeta); + index++; + } + } + + return new RowMetaAndData(rowMeta, rowData); + } + + /* + * 1. Block the other instances by means of a lock. + * 2. Try to locate an existing connection. + * 3. If it doesn't exist, it tries to take control of the routine to + * create an instance of PlcConnection and his wrapper. + * 4. Register the connection wrapper for global access. + * 5. If the connection to the PLC is made, then it creates the query + * and executes it. + * + */ + @Override + public boolean processRow() throws HopException { + Object[] r = getRow(); // Get row from input rowset & set row busy! + setLogLevel(LogLevel.DEBUG); + + if ((!meta.isNeverEnding() && data.rowsWritten >= data.rowLimit) && !isStopped()) { + setOutputDone(); // signal end to receiver(s) + return false; + } + + if (first) { + index.clear(); + plcfields.clear(); + //This performs a minimal check on the user item. + //It guarantees that the rates are within those managed by Plc4x. + meta.getFields().forEach((f) ->{ + plcfields.put(f.getName(),Plc4xPlcField.of(f.getItem())); + }); + first = false; + } + + lock.lock(); //(01) + try { + IHopMetadataProvider metaprovider = getMetadataProvider(); + connmeta = metaprovider.getSerializer(Plc4xConnection.class).load(meta.getConnection()); + if (connwrapper == null) { + connwrapper = (Plc4xWrapperConnection) getPipeline().getExtensionDataMap().get(meta.getConnection()); //(02) + if (connwrapper != null) connwrapper.retain(); + }; + + if (connmeta == null){ + logError( + BaseMessages.getString( + PKG, + "Plc4x.Read.Meta.Log.SetMetadata", + meta.getConnection())); + } + + if ((connmeta != null) && (connwrapper == null)){ + readRequest = null; + try{ + PlcConnection conn = new DefaultPlcDriverManager().getConnection(connmeta.getUrl()); //(03) + if (conn.isConnected()) { + connwrapper = new Plc4xWrapperConnection(conn); + getPipeline().getExtensionDataMap().put(meta.getConnection(), connwrapper); //(04) + } + } catch (Exception ex){ + setErrors(1L); + logError("Unable to create connection to PLC. " + ex.getMessage()); + } + } + } finally { + lock.unlock(); + } + + if ((connmeta != null) && (connwrapper != null)){ + if (connwrapper.getConnection().isConnected()){ + if (readRequest == null){ + PlcReadRequest.Builder builder = connwrapper.getConnection().readRequestBuilder(); //(05) + for (Plc4xGeneratorField field: meta.getFields()){ + builder.addTagAddress(field.getName(), field.getItem()); + } + readRequest = builder.build(); + } + try { + maxwait = Integer.parseInt(meta.getMaxwaitInMs()); + maxwait = (maxwait<100)?100:maxwait; + readResponse = readRequest.execute().get(maxwait, TimeUnit.MILLISECONDS); + + for (Plc4xGeneratorField field: meta.getFields()){ + field.setValue(readResponse.getString(field.getName())); + } + } catch (Exception ex) { + setErrors(1L); + logError("Unable read from PLC. " + ex.getMessage()); + } + + } else { + setErrors(1L); + logError("PLC is not connected."); + setOutputDone(); + return false; + } + + } else { + setErrors(1L); + logError("PLC connection don't exist."); + setOutputDone(); + return false; + } + + // + int interval = Integer.parseInt(meta.getIntervalInMs()); + + try { + Thread.sleep(interval); + } catch (InterruptedException ex) { + setErrors(1L); + logError(ex.getMessage()); + } + + r = data.outputRowMeta.cloneRow(data.outputRowData); + logBasic("Tamano de los datos: " + r.length); + data.prevDate = data.rowDate; + data.rowDate = new Date(); + int index = 0; + if (!Utils.isEmpty(meta.getRowTimeField())) { + r[index++] = data.rowDate; + } + if (!Utils.isEmpty(meta.getLastTimeField())) { + r[index++] = data.prevDate; + } + for (Plc4xGeneratorField field: meta.getFields()){ + if (field.getType().equalsIgnoreCase("Boolean")){ + r[index++] = Boolean.parseBoolean(field.getValue()); + } else if (field.getType().equalsIgnoreCase("Number")){ + r[index++] = Double.parseDouble(field.getValue()); + } else if (field.getType().equalsIgnoreCase("Integer")){ + r[index++] = Integer.parseInt(field.getValue()); + } + } + putRow(data.outputRowMeta, r ); // return your data + data.rowsWritten++; + return true; + } + + + @Override + public boolean init() { + try { + if(super.init()){ + // Determine the number of rows to generate... + data.rowLimit = Const.toLong(resolve(meta.getRowLimit()), -1L); + data.rowsWritten = 0L; + data.delay = Const.toLong(resolve(meta.getIntervalInMs()), -1L); + + if (data.rowLimit < 0L) { // Unable to parse + logError(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Wrong.RowLimit.Number")); + return false; // fail + } + + // Create a row (constants) with all the values in it... + List remarks = new ArrayList<>(); // stores the errors... + RowMetaAndData outputRow = buildRow(meta, remarks, getTransformName()); + if (!remarks.isEmpty()) { + for (int i = 0; i < remarks.size(); i++) { + CheckResult cr = (CheckResult) remarks.get(i); + logError(cr.getText()); + } + return false; + } + + data.outputRowData = outputRow.getData(); + data.outputRowMeta = outputRow.getRowMeta(); + + return true; + } + return false; + } catch (Exception ex){ + setErrors(1L); + logError("Error initializing transform", ex); + return false; + } + } + + /* + * Here, must perform the cleaning of any resource, main of the connection to + * the associated PLC. + */ + @Override + public void cleanup() { + super.cleanup(); + logBasic("Cleanup. Release connection."); + if (connwrapper != null) + connwrapper.release(); + } + + + /* + * Here, must perform the cleaning of any resource. + * 1. Check if we have reference to wrapper. + * 2. Release de reference to object. + * 3. The lastone remove the global reference to connection wrapper. + * 4. Clear local references. + */ + @Override + public void dispose() { + super.dispose(); + if (connwrapper != null) { + logBasic("Dispose. Release connection: " + connwrapper.refCnt()); + connwrapper.release(); + if (!connwrapper.getConnection().isConnected()){ + getPipeline().getExtensionDataMap().remove(meta.getConnection()); + } + connwrapper = null; + readRequest = null; + + } + } + + + + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsData.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsData.java new file mode 100644 index 00000000000..e39dad14568 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsData.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xsubs; + +import org.apache.plc4x.hop.transforms.plc4xinput.*; +import java.util.Date; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.pipeline.transform.BaseTransformData; +import org.apache.hop.pipeline.transform.ITransformData; + + +public class Plc4xSubsData extends BaseTransformData implements ITransformData { + + //The Plc4xConnection metadata + public String connection; + + public IRowMeta outputRowMeta; + public Object[] outputRowData; + + public long rowLimit; + public long rowsWritten; + public Date rowDate; + public Date prevDate; + public long delay; + + + + /** + * Default constructor for SampleData. + */ + public Plc4xSubsData() { + super(); + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsDialog.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsDialog.java new file mode 100644 index 00000000000..e5d14f2c8b0 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsDialog.java @@ -0,0 +1,601 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xsubs; + +import org.apache.plc4x.hop.transforms.plc4xinput.*; +import org.apache.hop.core.Const; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.row.value.ValueMetaFactory; +import org.apache.hop.core.util.Utils; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.PipelinePreviewFactory; +import org.apache.hop.pipeline.transform.BaseTransformMeta; +import org.apache.hop.pipeline.transform.ITransformDialog; +import org.apache.hop.ui.core.ConstUi; +import org.apache.hop.ui.core.dialog.BaseDialog; +import org.apache.hop.ui.core.dialog.EnterNumberDialog; +import org.apache.hop.ui.core.dialog.EnterTextDialog; +import org.apache.hop.ui.core.dialog.ErrorDialog; +import org.apache.hop.ui.core.dialog.PreviewRowsDialog; +import org.apache.hop.ui.core.widget.ColumnInfo; +import org.apache.hop.ui.core.widget.MetaSelectionLine; +import org.apache.hop.ui.core.widget.TableView; +import org.apache.hop.ui.core.widget.TextVar; +import org.apache.hop.ui.pipeline.dialog.PipelinePreviewProgressDialog; +import org.apache.hop.ui.pipeline.transform.BaseTransformDialog; +import org.apache.hop.ui.util.SwtSvgImageUtil; +import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.apache.plc4x.hop.transforms.util.Plc4xGeneratorField; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.*; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; + +public class Plc4xSubsDialog extends BaseTransformDialog implements ITransformDialog { + private static final Class PKG = Plc4xSubsDialog.class; // Needed by Translator + + private MetaSelectionLine wConnection; + + private Label wlLimit; + private TextVar wLimit; + + private Button wNeverEnding; + + private Label wlMaxwait; + private TextVar wMaxwait; + + private Label wlInterval; + private TextVar wInterval; + + private Label wlRowTimeField; + private TextVar wRowTimeField; + + private Label wlLastTimeField; + private TextVar wLastTimeField; + + private TableView wFields; + + private final Plc4xSubsMeta input; + + public Plc4xSubsDialog(Shell parent, IVariables variables , Object in, PipelineMeta pipelineMeta, String sname ) { + super( parent, variables, (BaseTransformMeta) in, pipelineMeta, sname ); + input = (Plc4xSubsMeta) in; + } + + @Override + public String open() { + Shell parent = getParent(); + + shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX | SWT.MIN); + props.setLook(shell); + setShellImage(shell, input); + + ModifyListener lsMod = e -> input.setChanged(); + changed = input.hasChanged(); + + FormLayout formLayout = new FormLayout(); + formLayout.marginWidth = Const.FORM_MARGIN; + formLayout.marginHeight = Const.FORM_MARGIN; + + shell.setLayout(formLayout); + shell.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.DialogTitle")); + + int middle = props.getMiddlePct(); + int margin = props.getMargin(); + + // Filename line + wlTransformName = new Label(shell, SWT.RIGHT); + wlTransformName.setText(BaseMessages.getString(PKG, "System.Label.TransformName")); + props.setLook(wlTransformName); + fdlTransformName = new FormData(); + fdlTransformName.left = new FormAttachment(0, 0); + fdlTransformName.right = new FormAttachment(middle, -margin); + fdlTransformName.top = new FormAttachment(0, margin); + wlTransformName.setLayoutData(fdlTransformName); + + wTransformName = new Text(shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + wTransformName.setText(transformName); + props.setLook(wTransformName); + wTransformName.addModifyListener(lsMod); + fdTransformName = new FormData(); + fdTransformName.left = new FormAttachment(middle, 0); + fdTransformName.top = new FormAttachment(0, margin); + fdTransformName.right = new FormAttachment(100, 0); + wTransformName.setLayoutData(fdTransformName); + + // Connection line + wConnection = + new MetaSelectionLine<>( + variables, + metadataProvider, + Plc4xConnection.class, + shell, + SWT.NONE, + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Connection.Label"), + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Connection.Tooltip")); + FormData fdConnection = new FormData(); + fdConnection.left = new FormAttachment(0, 0); + fdConnection.right = new FormAttachment(100, 0); + fdConnection.top = new FormAttachment(wTransformName, margin); + wConnection.setLayoutData(fdConnection); + props.setLook(wConnection); + try { + wConnection.fillItems(); + } catch (Exception e) { + new ErrorDialog(shell, "Error", "Error listing Cassandra connection metadata objects", e); + } + + Control lastControl = wConnection; + + wlLimit = new Label(shell, SWT.RIGHT); + wlLimit.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Limit.Label")); + props.setLook(wlLimit); + FormData fdlLimit = new FormData(); + fdlLimit.left = new FormAttachment(0, 0); + fdlLimit.right = new FormAttachment(middle, -margin); + fdlLimit.top = new FormAttachment(lastControl, margin); + wlLimit.setLayoutData(fdlLimit); + wLimit = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wLimit); + wLimit.addModifyListener(lsMod); + FormData fdLimit = new FormData(); + fdLimit.left = new FormAttachment(middle, 0); + fdLimit.top = new FormAttachment(lastControl, margin); + fdLimit.right = new FormAttachment(100, 0); + wLimit.setLayoutData(fdLimit); + lastControl = wLimit; + + Label wlNeverEnding = new Label(shell, SWT.RIGHT); + wlNeverEnding.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.NeverEnding.Label")); + props.setLook(wlNeverEnding); + FormData fdlNeverEnding = new FormData(); + fdlNeverEnding.left = new FormAttachment(0, 0); + fdlNeverEnding.right = new FormAttachment(middle, -margin); + fdlNeverEnding.top = new FormAttachment(lastControl, margin); + wlNeverEnding.setLayoutData(fdlNeverEnding); + wNeverEnding = new Button(shell, SWT.CHECK); + props.setLook(wNeverEnding); + wNeverEnding.addSelectionListener( + new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + setActive(); + input.setChanged(); + } + }); + FormData fdNeverEnding = new FormData(); + fdNeverEnding.left = new FormAttachment(middle, 0); + fdNeverEnding.top = new FormAttachment(wlNeverEnding, 0, SWT.CENTER); + fdNeverEnding.right = new FormAttachment(100, 0); + wNeverEnding.setLayoutData(fdNeverEnding); + lastControl = wlNeverEnding; + + wlMaxwait = new Label(shell, SWT.RIGHT); + wlMaxwait.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Maxwait.Label")); + props.setLook(wlMaxwait); + FormData fdlMaxwait = new FormData(); + fdlMaxwait.left = new FormAttachment(0, 0); + fdlMaxwait.right = new FormAttachment(middle, -margin); + fdlMaxwait.top = new FormAttachment(lastControl, margin); + wlMaxwait.setLayoutData(fdlMaxwait); + wMaxwait = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wMaxwait); + wMaxwait.addModifyListener(lsMod); + FormData fdMaxwait = new FormData(); + fdMaxwait.left = new FormAttachment(middle, 0); + fdMaxwait.top = new FormAttachment(lastControl, margin); + fdMaxwait.right = new FormAttachment(100, 0); + wMaxwait.setLayoutData(fdMaxwait); + lastControl = wMaxwait; + + wlInterval = new Label(shell, SWT.RIGHT); + wlInterval.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Interval.Label")); + props.setLook(wlInterval); + FormData fdlInterval = new FormData(); + fdlInterval.left = new FormAttachment(0, 0); + fdlInterval.right = new FormAttachment(middle, -margin); + fdlInterval.top = new FormAttachment(lastControl, margin); + wlInterval.setLayoutData(fdlInterval); + wInterval = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wInterval); + wInterval.addModifyListener(lsMod); + FormData fdInterval = new FormData(); + fdInterval.left = new FormAttachment(middle, 0); + fdInterval.top = new FormAttachment(lastControl, margin); + fdInterval.right = new FormAttachment(100, 0); + wInterval.setLayoutData(fdInterval); + lastControl = wInterval; + + /* + wlRowTimeField = new Label(shell, SWT.RIGHT); + wlRowTimeField.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.RowTimeField.Label")); + props.setLook(wlRowTimeField); + FormData fdlRowTimeField = new FormData(); + fdlRowTimeField.left = new FormAttachment(0, 0); + fdlRowTimeField.right = new FormAttachment(middle, -margin); + fdlRowTimeField.top = new FormAttachment(lastControl, margin); + wlRowTimeField.setLayoutData(fdlRowTimeField); + wRowTimeField = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wRowTimeField); + wRowTimeField.addModifyListener(lsMod); + FormData fdRowTimeField = new FormData(); + fdRowTimeField.left = new FormAttachment(middle, 0); + fdRowTimeField.top = new FormAttachment(lastControl, margin); + fdRowTimeField.right = new FormAttachment(100, 0); + wRowTimeField.setLayoutData(fdRowTimeField); + lastControl = wRowTimeField; + + wlLastTimeField = new Label(shell, SWT.RIGHT); + wlLastTimeField.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.LastTimeField.Label")); + props.setLook(wlLastTimeField); + FormData fdlLastTimeField = new FormData(); + fdlLastTimeField.left = new FormAttachment(0, 0); + fdlLastTimeField.right = new FormAttachment(middle, -margin); + fdlLastTimeField.top = new FormAttachment(lastControl, margin); + wlLastTimeField.setLayoutData(fdlLastTimeField); + wLastTimeField = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wLastTimeField); + wLastTimeField.addModifyListener(lsMod); + FormData fdLastTimeField = new FormData(); + fdLastTimeField.left = new FormAttachment(middle, 0); + fdLastTimeField.top = new FormAttachment(lastControl, margin); + fdLastTimeField.right = new FormAttachment(100, 0); + wLastTimeField.setLayoutData(fdLastTimeField); + lastControl = wLastTimeField; + */ + wOk = new Button(shell, SWT.PUSH); + wOk.setText(BaseMessages.getString(PKG, "System.Button.OK")); + wOk.addListener(SWT.Selection, e -> ok()); + wPreview = new Button(shell, SWT.PUSH); + wPreview.setText(BaseMessages.getString(PKG, "System.Button.Preview")); + wPreview.addListener(SWT.Selection, e -> preview()); + wCancel = new Button(shell, SWT.PUSH); + wCancel.setText(BaseMessages.getString(PKG, "System.Button.Cancel")); + wCancel.addListener(SWT.Selection, e -> cancel()); + + setButtonPositions(new Button[] {wOk, wPreview, wCancel}, margin, null); + + Label wlFields = new Label(shell, SWT.NONE); + wlFields.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Fields.Label")); + props.setLook(wlFields); + FormData fdlFields = new FormData(); + fdlFields.left = new FormAttachment(0, 0); + fdlFields.top = new FormAttachment(lastControl, margin); + wlFields.setLayoutData(fdlFields); + lastControl = wlFields; + + final int nrFields = input.getFields().size(); + + ColumnInfo[] colinf = + new ColumnInfo[] { + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Name"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Fields.Item"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Type"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + ValueMetaFactory.getValueMetaNames()), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Format"), + ColumnInfo.COLUMN_TYPE_FORMAT, + 2), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Length"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Precision"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Currency"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Decimal"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Group"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.Value"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "System.Column.SetEmptyString"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + new String[] { + BaseMessages.getString(PKG, "System.Combo.Yes"), + BaseMessages.getString(PKG, "System.Combo.No") + }) + }; + + wFields = + new TableView( + variables, + shell, + SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI, + colinf, + nrFields, + lsMod, + props); + + FormData fdFields = new FormData(); + fdFields.left = new FormAttachment(0, 0); + fdFields.top = new FormAttachment(lastControl, margin); + fdFields.right = new FormAttachment(100, 0); + fdFields.bottom = new FormAttachment(wOk, -2 * margin); + wFields.setLayoutData(fdFields); + + lsResize = + event -> { + Point size = shell.getSize(); + wFields.setSize(size.x - 10, size.y - 50); + wFields.table.setSize(size.x - 10, size.y - 50); + wFields.redraw(); + }; + shell.addListener(SWT.Resize, lsResize); + + getData(); + input.setChanged(changed); + + BaseDialog.defaultShellHandling(shell, c -> ok(), c -> cancel()); + + return transformName; + }; + + @Override + public void setActive() { + boolean neverEnding = wNeverEnding.getSelection(); + + wlLimit.setEnabled(!neverEnding); + wLimit.setEnabled(!neverEnding); + + //wlInterval.setEnabled(neverEnding); + //wInterval.setEnabled(neverEnding); + + //wlRowTimeField.setEnabled(neverEnding); + //wRowTimeField.setEnabled(neverEnding); + + //wlLastTimeField.setEnabled(neverEnding); + //wLastTimeField.setEnabled(neverEnding); + } + + + + private Image getImage() { + return SwtSvgImageUtil.getImage( shell.getDisplay(), getClass().getClassLoader(), "plc4x_toddy_read.svg", ConstUi.LARGE_ICON_SIZE, + ConstUi.LARGE_ICON_SIZE ); + } + + /** + * Copy information from the meta-data input to the dialog fields. + * + */ + public void getData() { + if (isDebug()) { + logDebug("getting fields info..."); + } + if (input.getConnection() == null) { + wConnection.setText(""); + } else { + wConnection.setText(input.getConnection()); + } + + wLimit.setText(input.getRowLimit()); + wNeverEnding.setSelection(input.isNeverEnding()); + wMaxwait.setText(Const.NVL(input.getMaxwaitInMs(), "")); + wInterval.setText(Const.NVL(input.getIntervalInMs(), "")); + // wRowTimeField.setText(Const.NVL(input.getRowTimeField(), "")); + //wLastTimeField.setText(Const.NVL(input.getLastTimeField(), "")); + + for (int i = 0; i < input.getFields().size(); i++) { + Plc4xGeneratorField field = input.getFields().get(i); + TableItem item = wFields.table.getItem(i); + int col = 1; + item.setText(col++, Const.NVL(field.getName(), "")); + + item.setText(col++, Const.NVL(field.getItem(), "")); + + String type = field.getType(); + String format = field.getFormat(); + String length = field.getLength() < 0 ? "" : ("" + field.getLength()); + String prec = field.getPrecision() < 0 ? "" : ("" + field.getPrecision()); + + String curr = field.getCurrency(); + String group = field.getGroup(); + String decim = field.getDecimal(); + String def = field.getValue(); + + item.setText(col++, Const.NVL(type, "")); + item.setText(col++, Const.NVL(format, "")); + item.setText(col++, Const.NVL(length, "")); + item.setText(col++, Const.NVL(prec, "")); + item.setText(col++, Const.NVL(curr, "")); + item.setText(col++, Const.NVL(decim, "")); + item.setText(col++, Const.NVL(group, "")); + item.setText(col++, Const.NVL(def, "")); + item.setText( + col++, + field.isSetEmptyString() + ? BaseMessages.getString(PKG, "System.Combo.Yes") + : BaseMessages.getString(PKG, "System.Combo.No")); + } + + wFields.setRowNums(); + wFields.optWidth(true); + + setActive(); + + wTransformName.selectAll(); + wTransformName.setFocus(); + } + + /** + * Stores the information from the dialog box in meta-data. + * + * @param meta + */ + private void getInfo( Plc4xSubsMeta meta) throws HopException { + meta.setConnection(wConnection.getText()); + meta.setRowLimit(wLimit.getText()); + meta.setNeverEnding(wNeverEnding.getSelection()); + meta.setMaxwaitInMs(wMaxwait.getText()); + meta.setIntervalInMs(wInterval.getText()); + //meta.setRowTimeField(wRowTimeField.getText()); + //meta.setLastTimeField(wLastTimeField.getText()); + + meta.getFields().clear(); + + // CHECKSTYLE:Indentation:OFF + for (TableItem item : wFields.getNonEmptyItems()) { + Plc4xGeneratorField field = new Plc4xGeneratorField(); + field.setName(item.getText(1)); + field.setItem(item.getText(2)); + field.setFormat(item.getText(4)); + field.setLength(Const.toInt(item.getText(5), -1)); + field.setPrecision(Const.toInt(item.getText(6), -1)); + field.setCurrency(item.getText(7)); + field.setDecimal(item.getText(8)); + field.setGroup(item.getText(9)); + field.setValue(field.isSetEmptyString() ? "" : item.getText(10)); + field.setSetEmptyString( + BaseMessages.getString(PKG, "System.Combo.Yes").equalsIgnoreCase(item.getText(11))); + field.setType(field.isSetEmptyString() ? "String" : item.getText(3)); + + meta.getFields().add(field); + } + } + + /** + * Cancel the dialog. + */ + private void cancel() { + transformName = null; + input.setChanged( changed ); + dispose(); + } + + private void ok() { + if (Utils.isEmpty(wTransformName.getText())) { + return; + } + + transformName = wTransformName.getText(); // return value + try { + getInfo(new Plc4xSubsMeta()); // to see if there is an exception + getInfo(input); // to put the content on the input structure for real if all is well. + dispose(); + } catch (HopException e) { + new ErrorDialog( + shell, + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title"), + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message"), + e); + } + } + + + /** + * Preview the data generated by this transform. This generates a pipeline using this transform & + * a dummy and previews it. + */ + private void preview() { + Plc4xSubsMeta oneMeta = new Plc4xSubsMeta(); + try { + getInfo(oneMeta); + } catch (HopException e) { + new ErrorDialog( + shell, + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title"), + BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message"), + e); + return; + } + + PipelineMeta previewMeta = + PipelinePreviewFactory.generatePreviewPipeline( + pipelineMeta.getMetadataProvider(), oneMeta, wTransformName.getText()); + + EnterNumberDialog numberDialog = + new EnterNumberDialog( + shell, + props.getDefaultPreviewSize(), + BaseMessages.getString(PKG, "System.Dialog.EnterPreviewSize.Title"), + BaseMessages.getString(PKG, "System.Dialog.EnterPreviewSize.Message")); + int previewSize = numberDialog.open(); + if (previewSize > 0) { + PipelinePreviewProgressDialog progressDialog = + new PipelinePreviewProgressDialog( + shell, + variables, + previewMeta, + new String[] {wTransformName.getText()}, + new int[] {previewSize}); + progressDialog.open(); + + Pipeline pipeline = progressDialog.getPipeline(); + String loggingText = progressDialog.getLoggingText(); + + if (!progressDialog.isCancelled()) { + if (pipeline.getResult() != null && pipeline.getResult().getNrErrors() > 0) { + EnterTextDialog etd = + new EnterTextDialog( + shell, + BaseMessages.getString(PKG, "System.Dialog.PreviewError.Title"), + BaseMessages.getString(PKG, "System.Dialog.PreviewError.Message"), + loggingText, + true); + etd.setReadOnly(); + etd.open(); + } + } + + PreviewRowsDialog prd = + new PreviewRowsDialog( + shell, + variables, + SWT.NONE, + wTransformName.getText(), + progressDialog.getPreviewRowsMeta(wTransformName.getText()), + progressDialog.getPreviewRows(wTransformName.getText()), + loggingText); + prd.open(); + } + } + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsMeta.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsMeta.java new file mode 100644 index 00000000000..35f15665bdb --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsMeta.java @@ -0,0 +1,310 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.plc4xsubs; + +import org.apache.plc4x.hop.transforms.plc4xinput.*; +import java.util.ArrayList; +import org.apache.hop.core.ICheckResult; +import org.apache.hop.core.annotations.Transform; +import org.apache.hop.core.exception.HopTransformException; +import org.apache.hop.core.exception.HopXmlException; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.core.xml.XmlHandler; +import org.apache.hop.metadata.api.IHopMetadataProvider; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.transform.BaseTransformMeta; +import org.apache.hop.pipeline.transform.ITransformMeta; +import org.apache.hop.pipeline.transform.TransformMeta; +import org.w3c.dom.Node; + +import java.util.List; +import org.apache.hop.core.Const; +import org.apache.hop.core.RowMetaAndData; +import org.apache.hop.core.row.IValueMeta; +import org.apache.hop.metadata.api.HopMetadataProperty; +import org.apache.hop.pipeline.transform.ITransformIOMeta; +import org.apache.hop.pipeline.transform.TransformIOMeta; +import org.apache.plc4x.hop.transforms.util.Plc4xGeneratorField; + +/** + * Meta data for the sample transform. + */ +@Transform( + id = "plc4x-subs", + name = "i18n::Plc4x.Read.Name", + description = "i18n::Plc4x.Read.Description", + image = "plc4x_subs.svg", + categoryDescription = "i18n:org.apache.plc4x.hop.transforms.plc4xinput:Plc4x.Category.plc4x", + documentationUrl = "https://plc4x.apache.org/users/integrations/apache-calcite.html" +) +public class Plc4xSubsMeta extends BaseTransformMeta implements ITransformMeta { + + private static final Class PKG = Plc4xSubsMeta.class; // Needed by Translator + + + @HopMetadataProperty( + key = "connection", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.Connection") + private String connection; + + @HopMetadataProperty( + key = "never_ending", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.NeverEnding") + private boolean neverEnding; + + @HopMetadataProperty( + key = "maxwait_in_ms", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.MaxwaitInMs") + private String maxwaitInMs; + + @HopMetadataProperty( + key = "interval_in_ms", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.IntervalInMs") + private String intervalInMs; + + @HopMetadataProperty( + key = "row_time_field", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.RowTimeField") + private String rowTimeField; + + @HopMetadataProperty( + key = "last_time_field", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.LastTimeField") + private String lastTimeField; + + @HopMetadataProperty( + key = "limit", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.RowLimit") + private String rowLimit; + + @HopMetadataProperty( + groupKey = "fields", + key = "field", + injectionGroupDescription = "Plc4x.Read.Meta.Injection.Fields", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.Fields") + private List fields; + + public Plc4xSubsMeta() { + fields = new ArrayList<>(); + + rowLimit = "10"; + neverEnding = false; + maxwaitInMs = "1000"; + intervalInMs = "5000"; + rowTimeField = "now"; + lastTimeField = "last"; + } + + public Plc4xSubsMeta(Plc4xSubsMeta m) { + this.connection = m.connection; + this.neverEnding = m.neverEnding; + this.intervalInMs = m.intervalInMs; + this.rowTimeField = m.rowTimeField; + this.lastTimeField = m.lastTimeField; + this.rowLimit = m.rowLimit; + this.fields = new ArrayList<>(); + for (Plc4xGeneratorField field : m.fields) { + this.fields.add(new Plc4xGeneratorField(field)); + } + } + + @Override + public Plc4xSubsMeta clone() { + return new Plc4xSubsMeta(this); + } + + + + @Override + public void getFields( IRowMeta inputRowMeta, String name, IRowMeta[] info, TransformMeta nextTransform, + IVariables variables, IHopMetadataProvider metadataProvider ) throws HopTransformException { + try { + logBasic("PASO 1"); + List remarks = new ArrayList<>(); + RowMetaAndData rowMetaAndData = Plc4xSubs.buildRow(this, remarks, name); + logBasic("PASO 2"); + if (!remarks.isEmpty()) { + logBasic("PASO 3"); + StringBuilder stringRemarks = new StringBuilder(); + for (ICheckResult remark : remarks) { + logBasic("PASO 3x: " + remark.toString()); + stringRemarks.append(remark.toString()).append(Const.CR); + } + logBasic("PASO 3.1"); + throw new HopTransformException(stringRemarks.toString()); + } + logBasic("PASO 4"); + for (IValueMeta valueMeta : rowMetaAndData.getRowMeta().getValueMetaList()) { + valueMeta.setOrigin(name); + } + logBasic("PASO 5"); + inputRowMeta.mergeRowMeta(rowMetaAndData.getRowMeta()); + } catch (Exception e) { + throw new HopTransformException(e); + } + } + + + public Plc4xSubs createTransform(TransformMeta transformMeta, Plc4xSubsData data, int copyNr, + PipelineMeta pipelineMeta, Pipeline pipeline ) { + return new Plc4xSubs( transformMeta, this, data, copyNr, pipelineMeta, pipeline ); + } + + public Plc4xSubsData getTransformData() { + return new Plc4xSubsData(); + } +/* + @Override + public void loadXml( Node transformNode, IHopMetadataProvider metadataProvider ) throws HopXmlException { + //load the saved values from the transformnode + String sampleValue = XmlHandler.getTagValue( transformNode, "sampleValue" ); + + } +*/ + @Override + public void setDefault() { + //default values when creating a new transform + } + + + /** + * Returns the Input/Output metadata for this transform. + * The generator transform only produces output, does not accept input! + * TransformIOMeta(inputAcceptor, outputProducer, inputOptional, outputDynamic, inputDynamic) + */ + @Override + public ITransformIOMeta getTransformIOMeta() { + return new TransformIOMeta(false, true, false, false, false, false); + } + + /** + * Gets Plc4xConnection metadata name. + * + * @return value of intervalInMs + */ + public String getConnection() { + return connection; + } + + /** @param connection */ + public void setConnection(String connection) { + this.connection = connection; + } + + + /** + * Gets neverEnding + * + * @return value of neverEnding + */ + public boolean isNeverEnding() { + return neverEnding; + } + + /** @param neverEnding The neverEnding to set */ + public void setNeverEnding(boolean neverEnding) { + this.neverEnding = neverEnding; + } + + /** + * Gets intervalInMs + * + * @return value of intervalInMs + */ + public String getMaxwaitInMs() { + return maxwaitInMs; + } + + /** @param intervalInMs The intervalInMs to set */ + public void setMaxwaitInMs(String maxwaitInMs) { + this.maxwaitInMs = maxwaitInMs; + } + + /** + * Gets intervalInMs + * + * @return value of intervalInMs + */ + public String getIntervalInMs() { + return intervalInMs; + } + + /** @param intervalInMs The intervalInMs to set */ + public void setIntervalInMs(String intervalInMs) { + this.intervalInMs = intervalInMs; + } + + /** + * Gets rowTimeField + * + * @return value of rowTimeField + */ + public String getRowTimeField() { + return rowTimeField; + } + + /** @param rowTimeField The rowTimeField to set */ + public void setRowTimeField(String rowTimeField) { + this.rowTimeField = rowTimeField; + } + + /** + * Gets lastTimeField + * + * @return value of lastTimeField + */ + public String getLastTimeField() { + return lastTimeField; + } + + /** @param lastTimeField The lastTimeField to set */ + public void setLastTimeField(String lastTimeField) { + this.lastTimeField = lastTimeField; + } + + /** + * Gets rowLimit + * + * @return value of rowLimit + */ + public String getRowLimit() { + return rowLimit; + } + + /** @param rowLimit The rowLimit to set */ + public void setRowLimit(String rowLimit) { + this.rowLimit = rowLimit; + } + + /** + * Gets fields + * + * @return value of fields + */ + public List getFields() { + return fields; + } + + /** @param fields The fields to set */ + public void setFields(List fields) { + this.fields = fields; + } + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xDataType.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xDataType.java new file mode 100644 index 00000000000..dc6df28d2a2 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xDataType.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.plc4x.hop.transforms.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// Code generated by code-generation. DO NOT EDIT. + +public enum Plc4xDataType { + BOOL((short) 1, (short) 1), + BYTE((short) 2, (short) 1), + WORD((short) 3, (short) 2), + DWORD((short) 4, (short) 4), + LWORD((short) 5, (short) 8), + SINT((short) 6, (short) 1), + INT((short) 7, (short) 2), + DINT((short) 8, (short) 4), + LINT((short) 9, (short) 8), + USINT((short) 10, (short) 1), + UINT((short) 11, (short) 2), + UDINT((short) 12, (short) 4), + ULINT((short) 13, (short) 8), + REAL((short) 14, (short) 4), + LREAL((short) 15, (short) 8), + TIME((short) 16, (short) 8), + LTIME((short) 17, (short) 8), + DATE((short) 18, (short) 8), + LDATE((short) 19, (short) 8), + TIME_OF_DAY((short) 20, (short) 8), + LTIME_OF_DAY((short) 21, (short) 8), + DATE_AND_TIME((short) 22, (short) 8), + LDATE_AND_TIME((short) 23, (short) 8), + CHAR((short) 24, (short) 1), + WCHAR((short) 25, (short) 2), + STRING((short) 26, (short) 1), + WSTRING((short) 27, (short) 2); + + private static final Logger logger = LoggerFactory.getLogger(Plc4xDataType.class); + + private static final Map map; + + static { + map = new HashMap<>(); + for (Plc4xDataType value : Plc4xDataType.values()) { + map.put((short) value.getValue(), value); + } + } + + private short value; + private short dataTypeSize; + + Plc4xDataType(short value, short dataTypeSize) { + this.value = value; + this.dataTypeSize = dataTypeSize; + } + + public short getValue() { + return value; + } + + public short getDataTypeSize() { + return dataTypeSize; + } + + public static Plc4xDataType firstEnumForFieldDataTypeSize(short fieldValue) { + for (Plc4xDataType _val : Plc4xDataType.values()) { + if (_val.getDataTypeSize() == fieldValue) { + return _val; + } + } + return null; + } + + public static List enumsForFieldDataTypeSize(short fieldValue) { + List _values = new ArrayList(); + for (Plc4xDataType _val : Plc4xDataType.values()) { + if (_val.getDataTypeSize() == fieldValue) { + _values.add(_val); + } + } + return _values; + } + + public static Plc4xDataType enumForValue(short value) { + if (!map.containsKey(value)) { + logger.error("No Plc4xDataType for value {}", value); + } + return map.get(value); + } + + public static Boolean isDefined(short value) { + return map.containsKey(value); + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xGeneratorField.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xGeneratorField.java new file mode 100644 index 00000000000..a676ee34221 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xGeneratorField.java @@ -0,0 +1,275 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.transforms.util; + +import org.apache.hop.metadata.api.HopMetadataProperty; + +import java.util.Objects; + +public class Plc4xGeneratorField { + + @HopMetadataProperty(injectionKeyDescription = "Plc4x.Read.Meta.Injection.Field.Name") + private String name; + + @HopMetadataProperty(injectionKeyDescription = "Plc4x.Read.Meta.Injection.Field.Item") + private String item; + + @HopMetadataProperty(injectionKeyDescription = "Plc4x.Read.Meta.Injection.Field.Type") + private String type; + + @HopMetadataProperty(injectionKeyDescription = "Plc4x.Read.Meta.Injection.Field.Format") + private String format; + + @HopMetadataProperty(injectionKeyDescription = "Plc4x.Read.Meta.Injection.Field.Length") + private int length; + + @HopMetadataProperty(injectionKeyDescription = "Plc4x.Read.Meta.Injection.Field.Precision") + private int precision; + + @HopMetadataProperty(injectionKeyDescription = "Plc4x.Read.Meta.Injection.Field.Currency") + private String currency; + + @HopMetadataProperty(injectionKeyDescription = "Plc4x.Read.Meta.Injection.Field.Decimal") + private String decimal; + + @HopMetadataProperty(injectionKeyDescription = "Plc4x.Read.Meta.Injection.Field.Group") + private String group; + + // Yeah, it has a key of "nullif", keep it for backward compatibility + @HopMetadataProperty( + key = "nullif", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.Field.Value") + private String value; + + @HopMetadataProperty( + key = "set_empty_string", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.Field.SetEmptyString") + private boolean setEmptyString; + + public Plc4xGeneratorField() {} + + public Plc4xGeneratorField(Plc4xGeneratorField f) { + this.name = f.name; + this.item = f.item; + this.type = f.type; + this.format = f.format; + this.length = f.length; + this.precision = f.precision; + this.currency = f.currency; + this.decimal = f.decimal; + this.group = f.group; + this.value = f.value; + this.setEmptyString = f.setEmptyString; + } + + public Plc4xGeneratorField( + String name, + String item, + String type, + String format, + int length, + int precision, + String currency, + String decimal, + String group, + String value, + boolean setEmptyString) { + this.name = name; + this.item = item; + this.type = type; + this.format = format; + this.length = length; + this.precision = precision; + this.currency = currency; + this.decimal = decimal; + this.group = group; + this.value = value; + this.setEmptyString = setEmptyString; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Plc4xGeneratorField that = (Plc4xGeneratorField) o; + return Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + /** + * Gets name + * + * @return value of name + */ + public String getName() { + return name; + } + + /** @param name The name to set */ + public void setName(String name) { + this.name = name; + } + + /** + * Gets Item + * + * @return value of name + */ + public String getItem() { + return item; + } + + /** @param name The name to set */ + public void setItem(String item) { + this.item = item; + } + + /** + * Gets type + * + * @return value of type + */ + public String getType() { + return type; + } + + /** @param type The type to set */ + public void setType(String type) { + this.type = type; + } + + /** + * Gets format + * + * @return value of format + */ + public String getFormat() { + return format; + } + + /** @param format The format to set */ + public void setFormat(String format) { + this.format = format; + } + + /** + * Gets length + * + * @return value of length + */ + public int getLength() { + return length; + } + + /** @param length The length to set */ + public void setLength(int length) { + this.length = length; + } + + /** + * Gets precision + * + * @return value of precision + */ + public int getPrecision() { + return precision; + } + + /** @param precision The precision to set */ + public void setPrecision(int precision) { + this.precision = precision; + } + + /** + * Gets currency + * + * @return value of currency + */ + public String getCurrency() { + return currency; + } + + /** @param currency The currency to set */ + public void setCurrency(String currency) { + this.currency = currency; + } + + /** + * Gets decimal + * + * @return value of decimal + */ + public String getDecimal() { + return decimal; + } + + /** @param decimal The decimal to set */ + public void setDecimal(String decimal) { + this.decimal = decimal; + } + + /** + * Gets group + * + * @return value of group + */ + public String getGroup() { + return group; + } + + /** @param group The group to set */ + public void setGroup(String group) { + this.group = group; + } + + /** + * Gets value + * + * @return value of value + */ + public String getValue() { + return value; + } + + /** @param value The value to set */ + public void setValue(String value) { + this.value = value; + } + + /** + * Gets setEmptyString + * + * @return value of setEmptyString + */ + public boolean isSetEmptyString() { + return setEmptyString; + } + + /** @param setEmptyString The setEmptyString to set */ + public void setSetEmptyString(boolean setEmptyString) { + this.setEmptyString = setEmptyString; + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcField.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcField.java new file mode 100644 index 00000000000..295dc9f1765 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcField.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.plc4x.hop.transforms.util; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.apache.plc4x.java.api.exceptions.PlcInvalidTagException; +import org.apache.plc4x.java.api.model.PlcTag; +import org.apache.plc4x.java.spi.generation.ParseException; +import org.apache.plc4x.java.spi.generation.SerializationException; +import org.apache.plc4x.java.spi.generation.WriteBuffer; +import org.apache.plc4x.java.spi.utils.Serializable; + +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/* +* Code taken from the Modbus driver implementation. +* This allows me to make the correct interpretation of the "Hop" values +* towards the writing fields. +* +* TODO: The HOP interpreter generates an error when processing +* the "Integer" fields. +*/ + +public class Plc4xPlcField implements PlcTag, Serializable { + + public static final Pattern ADDRESS_PATTERN = Pattern.compile("(?
[\\%a-zA-Z_\\.0-9]+)(:(?[a-zA-Z_]+))?(\\[(?\\d+)])?"); + + protected static final int PROTOCOL_ADDRESS_OFFSET = 1; + + private final String address; + + private final int quantity; + + private final Plc4xDataType dataType; + + public static Plc4xPlcField of(String addressString) { + if (Plc4xPlcField.matches(addressString)) { + Matcher matcher = ADDRESS_PATTERN.matcher(addressString); + + matcher.matches(); + + String address = matcher.group("address"); + + String quantityString = matcher.group("quantity"); + int quantity = quantityString != null ? Integer.parseInt(quantityString) : 1; + + Plc4xDataType dataType = (matcher.group("datatype") != null) ? Plc4xDataType.valueOf(matcher.group("datatype")) : Plc4xDataType.BOOL; + + + return new Plc4xPlcField(address, quantity, dataType); + } + + throw new PlcInvalidTagException("Unable to parse address: " + addressString); + } + + protected Plc4xPlcField(String address, Integer quantity, Plc4xDataType dataType) { + this.address = address; + + this.quantity = quantity != null ? quantity : 1; + + this.dataType = dataType != null ? dataType : Plc4xDataType.INT; + } + + public static boolean matches(String addressString) { + return ADDRESS_PATTERN.matcher(addressString).matches(); + } + + public String getAddress() { + return address; + } + + public int getNumberOfElements() { + return quantity; + } + + public int getLengthBytes() { + return quantity * dataType.getDataTypeSize(); + } + + @JsonIgnore + public int getLengthWords() { + return (int) ((quantity * (float) dataType.getDataTypeSize()) / 2.0f); + } + + public Plc4xDataType getDataType() { + return dataType; + } + + public String getPlcDataType() { + return dataType.name(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Plc4xPlcField)) { + return false; + } + Plc4xPlcField that = (Plc4xPlcField) o; + return address == that.address; + } + + @Override + public int hashCode() { + return Objects.hash(address); + } + + @Override + public String toString() { + return "Plc4xPlcField{" + + " address=" + address + + " datatype=" + dataType + + " quantity=" + quantity + + " }"; + } + + @Override + public void serialize(WriteBuffer wb) throws SerializationException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getAddressString() { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xWrapperConnection.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xWrapperConnection.java new file mode 100644 index 00000000000..6c6ea3602aa --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xWrapperConnection.java @@ -0,0 +1,60 @@ + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.plc4x.hop.transforms.util; + +import io.netty.util.AbstractReferenceCounted; +import io.netty.util.ReferenceCounted; +import org.apache.plc4x.java.api.PlcConnection; + +/** + * This is a wrapper around a PlcConnection connection from the Apache Plc4x library. + * Its goal is for it to be shared between the different transform that + * may be running simultaneously on the local or remote Hop engine. + * Its use with other kind of engines must be certified. + * The concept is very simple, the last to leave closes the connection. + */ +public class Plc4xWrapperConnection extends AbstractReferenceCounted { + + private final PlcConnection connection; + + public Plc4xWrapperConnection(PlcConnection connection){ + super(); + this.connection = connection; + } + + public PlcConnection getConnection(){ + return this.connection; + } + + @Override + protected void deallocate() { + try{ + connection.close(); + } catch (Exception ex){ + ex.printStackTrace(); + } + } + + + @Override + public ReferenceCounted touch(Object hint) { + return this; + } + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xevent/messages/messages_en_US.properties b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xevent/messages/messages_en_US.properties new file mode 100644 index 00000000000..b6bc8d9f8d5 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xevent/messages/messages_en_US.properties @@ -0,0 +1,69 @@ + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +Plc4x.Category.plc4x=Plc4x +Plc4x.Read.Name=Plc4x Event Transform +Plc4x.Read.Description=Plc4x Event Transform Description +Plc4x.Read.Shell.Title=Plc4x Event Transform Title +Plc4x.Read.TransformName.Label=Plc4x Event Sample Name + +Plc4x.Read.Meta.Injection.NeverEnding=Connection +Plc4x.Read.Meta.Injection.NeverEnding=Nerverending +Plc4x.Read.Meta.Injection.MaxwaitInMs=MaxwaitIn +Plc4x.Read.Meta.Injection.IntervalInMs=IntervalIn +Plc4x.Read.Meta.Injection.RowTimeField=RowTimeField +Plc4x.Read.Meta.Injection.LastTimeField=LastTimeField +Plc4x.Read.Meta.Injection.RowLimit=RowLimit +Plc4x.Read.Meta.Injection.Fields=Fields + +Plc4x.Read.Meta.Injection.Field.Name=Name +Plc4x.Read.Meta.Injection.Field.Item=Item +Plc4x.Read.Meta.Injection.Field.Type=Type +Plc4x.Read.Meta.Injection.Field.Format=Format +Plc4x.Read.Meta.Injection.Field.Length=Length +Plc4x.Read.Meta.Injection.Field.Precision=Precision +Plc4x.Read.Meta.Injection.Field.Units=Units +Plc4x.Read.Meta.Injection.Field.Decimal=Decimal +Plc4x.Read.Meta.Injection.Field.Group=Group +Plc4x.Read.Meta.Injection.Field.Value=Value +Plc4x.Read.Meta.Injection.Field.SetEmptyString=Empty + +Plc4x.Read.Meta.Illegal.Dialog.Settings.Message=The Message +Plc4x.Read.Meta.Dialog.Settings.Title=Dialog +Plc4x.Read.Meta.Dialog.DialogTitle=Plc4x Read transformer +Plc4x.Read.Meta.Dialog.Limit.Label=Limit +Plc4x.Read.Meta.Dialog.NeverEnding.Label=Never ending +Plc4x.Read.Meta.Dialog.Maxwait.Label=Max waiting +Plc4x.Read.Meta.Dialog.Interval.Label=Interval +Plc4x.Read.Meta.Dialog.RowTimeField.Label=Time +Plc4x.Read.Meta.Dialog.LastTimeField.Label=Last Time +Plc4x.Read.Meta.Dialog.Fields.Label=Fields +Plc4x.Read.Meta.Dialog.Fields.Item=Item +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title=Alert +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message=Message +Plc4x.Read.Meta.Dialog.Connection.Label=Connection EN +Plc4x.Read.Meta.Dialog.Connection.Tooltip=Plc4x connection metadata EN +Plc4x.Read.Meta.BuildRow.Error.Parsing.Number=Error parsing number +Plc4x.Read.Meta.BuildRow.Error.Parsing.Date=Error parsing date +Plc4x.Read.Meta.BuildRow.Error.Parsing.Integer=Error parsing integer +Plc4x.Read.Meta.BuildRow.Error.Parsing.BigNumber=Error parsing bignumber +Plc4x.Read.Meta.BuildRow.Error.Parsing.Timestamp=Error parsing timestamp +Plc4x.Read.Meta.CheckResult.SpecifyTypeError=Errot type +Plc4x.Read.Meta.Wrong.RowLimit.Number=Error in the number of row +System.Column.SetEmptyString=Set empty string? +Plc4x.Read.Meta.Log.SetMetadata=Check your connection setings +Plc4x.Read.Meta.Log.UnableToCreateConnection=Unable to create connection to PLC diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xevent/messages/messages_es_ES.properties b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xevent/messages/messages_es_ES.properties new file mode 100644 index 00000000000..4fba5312296 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xevent/messages/messages_es_ES.properties @@ -0,0 +1,69 @@ + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +Plc4x.Category.plc4x=Plc4x +Plc4x.Read.Name=Plc4x Event Transform +Plc4x.Read.Description=Plc4x Event Transform Description +Plc4x.Read.Shell.Title=Plc4x Event Transform Title +Plc4x.Read.TransformName.Label=Plc4x Event Sample Name + +Plc4x.Read.Meta.Injection.NeverEnding=Connection +Plc4x.Read.Meta.Injection.NeverEnding=Nerverending +Plc4x.Read.Meta.Injection.MaxwaitInMs=MaxwaitIn +Plc4x.Read.Meta.Injection.IntervalInMs=IntervalIn +Plc4x.Read.Meta.Injection.RowTimeField=RowTimeField +Plc4x.Read.Meta.Injection.LastTimeField=LastTimeField +Plc4x.Read.Meta.Injection.RowLimit=RowLimit +Plc4x.Read.Meta.Injection.Fields=Fields + +Plc4x.Read.Meta.Injection.Field.Name=Name +Plc4x.Read.Meta.Injection.Field.Item=Item +Plc4x.Read.Meta.Injection.Field.Type=Type +Plc4x.Read.Meta.Injection.Field.Format=Format +Plc4x.Read.Meta.Injection.Field.Length=Length +Plc4x.Read.Meta.Injection.Field.Precision=Precision +Plc4x.Read.Meta.Injection.Field.Units=Units +Plc4x.Read.Meta.Injection.Field.Decimal=Decimal +Plc4x.Read.Meta.Injection.Field.Group=Group +Plc4x.Read.Meta.Injection.Field.Value=Value +Plc4x.Read.Meta.Injection.Field.SetEmptyString=Empty + +Plc4x.Read.Meta.Illegal.Dialog.Settings.Message=The Message +Plc4x.Read.Meta.Dialog.Settings.Title=Dialog +Plc4x.Read.Meta.Dialog.DialogTitle=Plc4x Read transformer +Plc4x.Read.Meta.Dialog.Limit.Label=Limit +Plc4x.Read.Meta.Dialog.NeverEnding.Label=Bucle sin fin +Plc4x.Read.Meta.Dialog.Maxwait.Label=Max waiting +Plc4x.Read.Meta.Dialog.Interval.Label=Interval +Plc4x.Read.Meta.Dialog.RowTimeField.Label=Time +Plc4x.Read.Meta.Dialog.LastTimeField.Label=Last Time +Plc4x.Read.Meta.Dialog.Fields.Label=Fields +Plc4x.Read.Meta.Dialog.Fields.Item=Item +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title=Alert +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message=Message +Plc4x.Read.Meta.Dialog.Connection.Label=Connection ES +Plc4x.Read.Meta.Dialog.Connection.Tooltip=Plc4x connection metadata ES +Plc4x.Read.Meta.BuildRow.Error.Parsing.Number=Error parsing number +Plc4x.Read.Meta.BuildRow.Error.Parsing.Date=Error parsing date +Plc4x.Read.Meta.BuildRow.Error.Parsing.Integer=Error parsing integer +Plc4x.Read.Meta.BuildRow.Error.Parsing.BigNumber=Error parsing bignumber +Plc4x.Read.Meta.BuildRow.Error.Parsing.Timestamp=Error parsing timestamp +Plc4x.Read.Meta.CheckResult.SpecifyTypeError=Errot type +Plc4x.Read.Meta.Wrong.RowLimit.Number=Error in the number of row +System.Column.SetEmptyString=Set empty string? +Plc4x.Read.Meta.Log.SetMetadata=Check your connection setings +Plc4x.Read.Meta.Log.UnableToCreateConnection=Unable to create connection to PLC diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xinput/messages/messages_en_US.properties b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xinput/messages/messages_en_US.properties new file mode 100644 index 00000000000..59072612a7e --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xinput/messages/messages_en_US.properties @@ -0,0 +1,69 @@ + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +Plc4x.Category.plc4x=Plc4x +Plc4x.Read.Name=Plc4x Read Transform +Plc4x.Read.Description=Plc4x Read Transform Description +Plc4x.Read.Shell.Title=Plc4x Read Transform Title +Plc4x.Read.TransformName.Label=Plc4x Read Sample Name + +Plc4x.Read.Meta.Injection.NeverEnding=Connection +Plc4x.Read.Meta.Injection.NeverEnding=Nerverending +Plc4x.Read.Meta.Injection.MaxwaitInMs=MaxwaitIn +Plc4x.Read.Meta.Injection.IntervalInMs=IntervalIn +Plc4x.Read.Meta.Injection.RowTimeField=RowTimeField +Plc4x.Read.Meta.Injection.LastTimeField=LastTimeField +Plc4x.Read.Meta.Injection.RowLimit=RowLimit +Plc4x.Read.Meta.Injection.Fields=Fields + +Plc4x.Read.Meta.Injection.Field.Name=Name +Plc4x.Read.Meta.Injection.Field.Item=Item +Plc4x.Read.Meta.Injection.Field.Type=Type +Plc4x.Read.Meta.Injection.Field.Format=Format +Plc4x.Read.Meta.Injection.Field.Length=Length +Plc4x.Read.Meta.Injection.Field.Precision=Precision +Plc4x.Read.Meta.Injection.Field.Units=Units +Plc4x.Read.Meta.Injection.Field.Decimal=Decimal +Plc4x.Read.Meta.Injection.Field.Group=Group +Plc4x.Read.Meta.Injection.Field.Value=Value +Plc4x.Read.Meta.Injection.Field.SetEmptyString=Empty + +Plc4x.Read.Meta.Illegal.Dialog.Settings.Message=The Message +Plc4x.Read.Meta.Dialog.Settings.Title=Dialog +Plc4x.Read.Meta.Dialog.DialogTitle=Plc4x Read transformer +Plc4x.Read.Meta.Dialog.Limit.Label=Limit +Plc4x.Read.Meta.Dialog.NeverEnding.Label=Never ending +Plc4x.Read.Meta.Dialog.Maxwait.Label=Max waiting +Plc4x.Read.Meta.Dialog.Interval.Label=Interval +Plc4x.Read.Meta.Dialog.RowTimeField.Label=Time +Plc4x.Read.Meta.Dialog.LastTimeField.Label=Last Time +Plc4x.Read.Meta.Dialog.Fields.Label=Fields +Plc4x.Read.Meta.Dialog.Fields.Item=Item +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title=Alert +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message=Message +Plc4x.Read.Meta.Dialog.Connection.Label=Connection EN +Plc4x.Read.Meta.Dialog.Connection.Tooltip=Plc4x connection metadata EN +Plc4x.Read.Meta.BuildRow.Error.Parsing.Number=Error parsing number +Plc4x.Read.Meta.BuildRow.Error.Parsing.Date=Error parsing date +Plc4x.Read.Meta.BuildRow.Error.Parsing.Integer=Error parsing integer +Plc4x.Read.Meta.BuildRow.Error.Parsing.BigNumber=Error parsing bignumber +Plc4x.Read.Meta.BuildRow.Error.Parsing.Timestamp=Error parsing timestamp +Plc4x.Read.Meta.CheckResult.SpecifyTypeError=Errot type +Plc4x.Read.Meta.Wrong.RowLimit.Number=Error in the number of row +System.Column.SetEmptyString=Set empty string? +Plc4x.Read.Meta.Log.SetMetadata=Check your connection setings +Plc4x.Read.Meta.Log.UnableToCreateConnection=Unable to create connection to PLC diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xinput/messages/messages_es_ES.properties b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xinput/messages/messages_es_ES.properties new file mode 100644 index 00000000000..20a5d8f4b2f --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xinput/messages/messages_es_ES.properties @@ -0,0 +1,69 @@ + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +Plc4x.Category.plc4x=Plc4x +Plc4x.Read.Name=Plc4x Read Transform +Plc4x.Read.Description=Plc4x Read Transform Description +Plc4x.Read.Shell.Title=Plc4x Read Transform Title +Plc4x.Read.TransformName.Label=Plc4x Read Sample Name + +Plc4x.Read.Meta.Injection.NeverEnding=Connection +Plc4x.Read.Meta.Injection.NeverEnding=Nerverending +Plc4x.Read.Meta.Injection.MaxwaitInMs=MaxwaitIn +Plc4x.Read.Meta.Injection.IntervalInMs=IntervalIn +Plc4x.Read.Meta.Injection.RowTimeField=RowTimeField +Plc4x.Read.Meta.Injection.LastTimeField=LastTimeField +Plc4x.Read.Meta.Injection.RowLimit=RowLimit +Plc4x.Read.Meta.Injection.Fields=Fields + +Plc4x.Read.Meta.Injection.Field.Name=Name +Plc4x.Read.Meta.Injection.Field.Item=Item +Plc4x.Read.Meta.Injection.Field.Type=Type +Plc4x.Read.Meta.Injection.Field.Format=Format +Plc4x.Read.Meta.Injection.Field.Length=Length +Plc4x.Read.Meta.Injection.Field.Precision=Precision +Plc4x.Read.Meta.Injection.Field.Units=Units +Plc4x.Read.Meta.Injection.Field.Decimal=Decimal +Plc4x.Read.Meta.Injection.Field.Group=Group +Plc4x.Read.Meta.Injection.Field.Value=Value +Plc4x.Read.Meta.Injection.Field.SetEmptyString=Empty + +Plc4x.Read.Meta.Illegal.Dialog.Settings.Message=The Message +Plc4x.Read.Meta.Dialog.Settings.Title=Dialog +Plc4x.Read.Meta.Dialog.DialogTitle=Plc4x Read transformer +Plc4x.Read.Meta.Dialog.Limit.Label=Limit +Plc4x.Read.Meta.Dialog.NeverEnding.Label=Bucle sin fin +Plc4x.Read.Meta.Dialog.Maxwait.Label=Max waiting +Plc4x.Read.Meta.Dialog.Interval.Label=Interval +Plc4x.Read.Meta.Dialog.RowTimeField.Label=Time +Plc4x.Read.Meta.Dialog.LastTimeField.Label=Last Time +Plc4x.Read.Meta.Dialog.Fields.Label=Fields +Plc4x.Read.Meta.Dialog.Fields.Item=Item +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title=Alert +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message=Message +Plc4x.Read.Meta.Dialog.Connection.Label=Connection ES +Plc4x.Read.Meta.Dialog.Connection.Tooltip=Plc4x connection metadata ES +Plc4x.Read.Meta.BuildRow.Error.Parsing.Number=Error parsing number +Plc4x.Read.Meta.BuildRow.Error.Parsing.Date=Error parsing date +Plc4x.Read.Meta.BuildRow.Error.Parsing.Integer=Error parsing integer +Plc4x.Read.Meta.BuildRow.Error.Parsing.BigNumber=Error parsing bignumber +Plc4x.Read.Meta.BuildRow.Error.Parsing.Timestamp=Error parsing timestamp +Plc4x.Read.Meta.CheckResult.SpecifyTypeError=Errot type +Plc4x.Read.Meta.Wrong.RowLimit.Number=Error in the number of row +System.Column.SetEmptyString=Set empty string? +Plc4x.Read.Meta.Log.SetMetadata=Check your connection setings +Plc4x.Read.Meta.Log.UnableToCreateConnection=Unable to create connection to PLC diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xoutput/messages/messages_en_US.properties b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xoutput/messages/messages_en_US.properties new file mode 100644 index 00000000000..8bdd7fd697a --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xoutput/messages/messages_en_US.properties @@ -0,0 +1,69 @@ + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +Plc4x.Category.plc4x=Plc4x +Plc4x.Read.Name=Plc4x Write Transform +Plc4x.Read.Description=Plc4x Write Transform Description +Plc4x.Read.Shell.Title=Plc4x Write Transform Title +Plc4x.Read.TransformName.Label=Plc4x Write Sample Name + +Plc4x.Read.Meta.Injection.NeverEnding=Connection +Plc4x.Read.Meta.Injection.NeverEnding=Nerverending +Plc4x.Read.Meta.Injection.MaxwaitInMs=MaxwaitIn +Plc4x.Read.Meta.Injection.IntervalInMs=IntervalIn +Plc4x.Read.Meta.Injection.RowTimeField=RowTimeField +Plc4x.Read.Meta.Injection.LastTimeField=LastTimeField +Plc4x.Read.Meta.Injection.RowLimit=RowLimit +Plc4x.Read.Meta.Injection.Fields=Fields + +Plc4x.Read.Meta.Injection.Field.Name=Name +Plc4x.Read.Meta.Injection.Field.Item=Item +Plc4x.Read.Meta.Injection.Field.Type=Type +Plc4x.Read.Meta.Injection.Field.Format=Format +Plc4x.Read.Meta.Injection.Field.Length=Length +Plc4x.Read.Meta.Injection.Field.Precision=Precision +Plc4x.Read.Meta.Injection.Field.Units=Units +Plc4x.Read.Meta.Injection.Field.Decimal=Decimal +Plc4x.Read.Meta.Injection.Field.Group=Group +Plc4x.Read.Meta.Injection.Field.Value=Value +Plc4x.Read.Meta.Injection.Field.SetEmptyString=Empty + +Plc4x.Read.Meta.Illegal.Dialog.Settings.Message=The Message +Plc4x.Read.Meta.Dialog.Settings.Title=Dialog +Plc4x.Read.Meta.Dialog.DialogTitle=Plc4x Read transformer +Plc4x.Read.Meta.Dialog.Limit.Label=Limit +Plc4x.Read.Meta.Dialog.NeverEnding.Label=Never ending +Plc4x.Read.Meta.Dialog.Maxwait.Label=Max waiting +Plc4x.Read.Meta.Dialog.Interval.Label=Interval +Plc4x.Read.Meta.Dialog.RowTimeField.Label=Time +Plc4x.Read.Meta.Dialog.LastTimeField.Label=Last Time +Plc4x.Read.Meta.Dialog.Fields.Label=Fields +Plc4x.Read.Meta.Dialog.Fields.Item=Item +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title=Alert +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message=Message +Plc4x.Read.Meta.Dialog.Connection.Label=Connection EN +Plc4x.Read.Meta.Dialog.Connection.Tooltip=Plc4x connection metadata EN +Plc4x.Read.Meta.BuildRow.Error.Parsing.Number=Error parsing number +Plc4x.Read.Meta.BuildRow.Error.Parsing.Date=Error parsing date +Plc4x.Read.Meta.BuildRow.Error.Parsing.Integer=Error parsing integer +Plc4x.Read.Meta.BuildRow.Error.Parsing.BigNumber=Error parsing bignumber +Plc4x.Read.Meta.BuildRow.Error.Parsing.Timestamp=Error parsing timestamp +Plc4x.Read.Meta.CheckResult.SpecifyTypeError=Errot type +Plc4x.Read.Meta.Wrong.RowLimit.Number=Error in the number of row +System.Column.SetEmptyString=Set empty string? +Plc4x.Read.Meta.Log.SetMetadata=Check your connection setings +Plc4x.Read.Meta.Log.UnableToCreateConnection=Unable to create connection to PLC diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xoutput/messages/messages_es_ES.properties b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xoutput/messages/messages_es_ES.properties new file mode 100644 index 00000000000..b4d048a18c5 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xoutput/messages/messages_es_ES.properties @@ -0,0 +1,69 @@ + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +Plc4x.Category.plc4x=Plc4x +Plc4x.Read.Name=Plc4x Write Transform +Plc4x.Read.Description=Plc4x Write Transform Description +Plc4x.Read.Shell.Title=Plc4x Write Transform Title +Plc4x.Read.TransformName.Label=Plc4x Write Sample Name + +Plc4x.Read.Meta.Injection.NeverEnding=Connection +Plc4x.Read.Meta.Injection.NeverEnding=Nerverending +Plc4x.Read.Meta.Injection.MaxwaitInMs=MaxwaitIn +Plc4x.Read.Meta.Injection.IntervalInMs=IntervalIn +Plc4x.Read.Meta.Injection.RowTimeField=RowTimeField +Plc4x.Read.Meta.Injection.LastTimeField=LastTimeField +Plc4x.Read.Meta.Injection.RowLimit=RowLimit +Plc4x.Read.Meta.Injection.Fields=Fields + +Plc4x.Read.Meta.Injection.Field.Name=Name +Plc4x.Read.Meta.Injection.Field.Item=Item +Plc4x.Read.Meta.Injection.Field.Type=Type +Plc4x.Read.Meta.Injection.Field.Format=Format +Plc4x.Read.Meta.Injection.Field.Length=Length +Plc4x.Read.Meta.Injection.Field.Precision=Precision +Plc4x.Read.Meta.Injection.Field.Units=Units +Plc4x.Read.Meta.Injection.Field.Decimal=Decimal +Plc4x.Read.Meta.Injection.Field.Group=Group +Plc4x.Read.Meta.Injection.Field.Value=Value +Plc4x.Read.Meta.Injection.Field.SetEmptyString=Empty + +Plc4x.Read.Meta.Illegal.Dialog.Settings.Message=The Message +Plc4x.Read.Meta.Dialog.Settings.Title=Dialog +Plc4x.Read.Meta.Dialog.DialogTitle=Plc4x Read transformer +Plc4x.Read.Meta.Dialog.Limit.Label=Limit +Plc4x.Read.Meta.Dialog.NeverEnding.Label=Bucle sin fin +Plc4x.Read.Meta.Dialog.Maxwait.Label=Max waiting +Plc4x.Read.Meta.Dialog.Interval.Label=Interval +Plc4x.Read.Meta.Dialog.RowTimeField.Label=Time +Plc4x.Read.Meta.Dialog.LastTimeField.Label=Last Time +Plc4x.Read.Meta.Dialog.Fields.Label=Fields +Plc4x.Read.Meta.Dialog.Fields.Item=Item +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title=Alert +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message=Message +Plc4x.Read.Meta.Dialog.Connection.Label=Connection ES +Plc4x.Read.Meta.Dialog.Connection.Tooltip=Plc4x connection metadata ES +Plc4x.Read.Meta.BuildRow.Error.Parsing.Number=Error parsing number +Plc4x.Read.Meta.BuildRow.Error.Parsing.Date=Error parsing date +Plc4x.Read.Meta.BuildRow.Error.Parsing.Integer=Error parsing integer +Plc4x.Read.Meta.BuildRow.Error.Parsing.BigNumber=Error parsing bignumber +Plc4x.Read.Meta.BuildRow.Error.Parsing.Timestamp=Error parsing timestamp +Plc4x.Read.Meta.CheckResult.SpecifyTypeError=Errot type +Plc4x.Read.Meta.Wrong.RowLimit.Number=Error in the number of row +System.Column.SetEmptyString=Set empty string? +Plc4x.Read.Meta.Log.SetMetadata=Check your connection setings +Plc4x.Read.Meta.Log.UnableToCreateConnection=Unable to create connection to PLC diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xsubs/messages/messages_en_US.properties b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xsubs/messages/messages_en_US.properties new file mode 100644 index 00000000000..cbcf6a63dac --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xsubs/messages/messages_en_US.properties @@ -0,0 +1,69 @@ + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +Plc4x.Category.plc4x=Plc4x +Plc4x.Read.Name=Plc4x Subscription Transform +Plc4x.Read.Description=Plc4x Subscription Transform Description +Plc4x.Read.Shell.Title=Plc4x Subscription Transform Title +Plc4x.Read.TransformName.Label=Plc4x Subscription Sample Name + +Plc4x.Read.Meta.Injection.NeverEnding=Connection +Plc4x.Read.Meta.Injection.NeverEnding=Nerverending +Plc4x.Read.Meta.Injection.MaxwaitInMs=MaxwaitIn +Plc4x.Read.Meta.Injection.IntervalInMs=IntervalIn +Plc4x.Read.Meta.Injection.RowTimeField=RowTimeField +Plc4x.Read.Meta.Injection.LastTimeField=LastTimeField +Plc4x.Read.Meta.Injection.RowLimit=RowLimit +Plc4x.Read.Meta.Injection.Fields=Fields + +Plc4x.Read.Meta.Injection.Field.Name=Name +Plc4x.Read.Meta.Injection.Field.Item=Item +Plc4x.Read.Meta.Injection.Field.Type=Type +Plc4x.Read.Meta.Injection.Field.Format=Format +Plc4x.Read.Meta.Injection.Field.Length=Length +Plc4x.Read.Meta.Injection.Field.Precision=Precision +Plc4x.Read.Meta.Injection.Field.Units=Units +Plc4x.Read.Meta.Injection.Field.Decimal=Decimal +Plc4x.Read.Meta.Injection.Field.Group=Group +Plc4x.Read.Meta.Injection.Field.Value=Value +Plc4x.Read.Meta.Injection.Field.SetEmptyString=Empty + +Plc4x.Read.Meta.Illegal.Dialog.Settings.Message=The Message +Plc4x.Read.Meta.Dialog.Settings.Title=Dialog +Plc4x.Read.Meta.Dialog.DialogTitle=Plc4x Read transformer +Plc4x.Read.Meta.Dialog.Limit.Label=Limit +Plc4x.Read.Meta.Dialog.NeverEnding.Label=Never ending +Plc4x.Read.Meta.Dialog.Maxwait.Label=Max waiting +Plc4x.Read.Meta.Dialog.Interval.Label=Interval +Plc4x.Read.Meta.Dialog.RowTimeField.Label=Time +Plc4x.Read.Meta.Dialog.LastTimeField.Label=Last Time +Plc4x.Read.Meta.Dialog.Fields.Label=Fields +Plc4x.Read.Meta.Dialog.Fields.Item=Item +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title=Alert +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message=Message +Plc4x.Read.Meta.Dialog.Connection.Label=Connection EN +Plc4x.Read.Meta.Dialog.Connection.Tooltip=Plc4x connection metadata EN +Plc4x.Read.Meta.BuildRow.Error.Parsing.Number=Error parsing number +Plc4x.Read.Meta.BuildRow.Error.Parsing.Date=Error parsing date +Plc4x.Read.Meta.BuildRow.Error.Parsing.Integer=Error parsing integer +Plc4x.Read.Meta.BuildRow.Error.Parsing.BigNumber=Error parsing bignumber +Plc4x.Read.Meta.BuildRow.Error.Parsing.Timestamp=Error parsing timestamp +Plc4x.Read.Meta.CheckResult.SpecifyTypeError=Errot type +Plc4x.Read.Meta.Wrong.RowLimit.Number=Error in the number of row +System.Column.SetEmptyString=Set empty string? +Plc4x.Read.Meta.Log.SetMetadata=Check your connection setings +Plc4x.Read.Meta.Log.UnableToCreateConnection=Unable to create connection to PLC diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xsubs/messages/messages_es_ES.properties b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xsubs/messages/messages_es_ES.properties new file mode 100644 index 00000000000..44279b8dec2 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xsubs/messages/messages_es_ES.properties @@ -0,0 +1,69 @@ + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +Plc4x.Category.plc4x=Plc4x +Plc4x.Read.Name=Plc4x Subscription Transform +Plc4x.Read.Description=Plc4x Subscription Transform Description +Plc4x.Read.Shell.Title=Plc4x Subscription Transform Title +Plc4x.Read.TransformName.Label=Plc4x Subscription Sample Name + +Plc4x.Read.Meta.Injection.NeverEnding=Connection +Plc4x.Read.Meta.Injection.NeverEnding=Nerverending +Plc4x.Read.Meta.Injection.MaxwaitInMs=MaxwaitIn +Plc4x.Read.Meta.Injection.IntervalInMs=IntervalIn +Plc4x.Read.Meta.Injection.RowTimeField=RowTimeField +Plc4x.Read.Meta.Injection.LastTimeField=LastTimeField +Plc4x.Read.Meta.Injection.RowLimit=RowLimit +Plc4x.Read.Meta.Injection.Fields=Fields + +Plc4x.Read.Meta.Injection.Field.Name=Name +Plc4x.Read.Meta.Injection.Field.Item=Item +Plc4x.Read.Meta.Injection.Field.Type=Type +Plc4x.Read.Meta.Injection.Field.Format=Format +Plc4x.Read.Meta.Injection.Field.Length=Length +Plc4x.Read.Meta.Injection.Field.Precision=Precision +Plc4x.Read.Meta.Injection.Field.Units=Units +Plc4x.Read.Meta.Injection.Field.Decimal=Decimal +Plc4x.Read.Meta.Injection.Field.Group=Group +Plc4x.Read.Meta.Injection.Field.Value=Value +Plc4x.Read.Meta.Injection.Field.SetEmptyString=Empty + +Plc4x.Read.Meta.Illegal.Dialog.Settings.Message=The Message +Plc4x.Read.Meta.Dialog.Settings.Title=Dialog +Plc4x.Read.Meta.Dialog.DialogTitle=Plc4x Read transformer +Plc4x.Read.Meta.Dialog.Limit.Label=Limit +Plc4x.Read.Meta.Dialog.NeverEnding.Label=Bucle sin fin +Plc4x.Read.Meta.Dialog.Maxwait.Label=Max waiting +Plc4x.Read.Meta.Dialog.Interval.Label=Interval +Plc4x.Read.Meta.Dialog.RowTimeField.Label=Time +Plc4x.Read.Meta.Dialog.LastTimeField.Label=Last Time +Plc4x.Read.Meta.Dialog.Fields.Label=Fields +Plc4x.Read.Meta.Dialog.Fields.Item=Item +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Title=Alert +Plc4x.Read.Meta.Dialog.Illegal.Dialog.Settings.Message=Message +Plc4x.Read.Meta.Dialog.Connection.Label=Connection ES +Plc4x.Read.Meta.Dialog.Connection.Tooltip=Plc4x connection metadata ES +Plc4x.Read.Meta.BuildRow.Error.Parsing.Number=Error parsing number +Plc4x.Read.Meta.BuildRow.Error.Parsing.Date=Error parsing date +Plc4x.Read.Meta.BuildRow.Error.Parsing.Integer=Error parsing integer +Plc4x.Read.Meta.BuildRow.Error.Parsing.BigNumber=Error parsing bignumber +Plc4x.Read.Meta.BuildRow.Error.Parsing.Timestamp=Error parsing timestamp +Plc4x.Read.Meta.CheckResult.SpecifyTypeError=Errot type +Plc4x.Read.Meta.Wrong.RowLimit.Number=Error in the number of row +System.Column.SetEmptyString=Set empty string? +Plc4x.Read.Meta.Log.SetMetadata=Check your connection setings +Plc4x.Read.Meta.Log.UnableToCreateConnection=Unable to create connection to PLC diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_action.svg b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_action.svg new file mode 100644 index 00000000000..01694ecd5df --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_action.svg @@ -0,0 +1,1306 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_event.svg b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_event.svg new file mode 100644 index 00000000000..21ed5ecb1ed --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_event.svg @@ -0,0 +1,822 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_read.svg b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_read.svg new file mode 100644 index 00000000000..c67b42523ad --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_read.svg @@ -0,0 +1,813 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_subs.svg b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_subs.svg new file mode 100644 index 00000000000..87f84f3f855 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_subs.svg @@ -0,0 +1,743 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_write.svg b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_write.svg new file mode 100644 index 00000000000..9b295c3ea71 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/plc4x_write.svg @@ -0,0 +1,810 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/pom.xml b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/pom.xml new file mode 100644 index 00000000000..214a8dc009f --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/pom.xml @@ -0,0 +1,138 @@ + + + + 4.0.0 + + org.apache.plc4x + hop-plc4x-utils + 0.11.0-SNAPSHOT + + plc4x-hop-grafana + jar + PLC4J: Integrations: Apache Hop: Grafana Post + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + org.jboss.jandex + jandex-maven-plugin + 1.0.8 + + + make-index + + jandex + + + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + io.netty:netty-common:jar:${netty.version} + io.netty:netty-all:jar:${netty.version} + commons-lang:commons-lang:jar:2.6 + xml-apis:xml-apis:jar:1.4.01 + + + + + + + + + org.apache.httpcomponents + httpclient + 4.5.13 + + + org.apache.hop + hop-core + ${hop.version} + + + * + * + + + + + org.apache.hop + hop-engine + ${hop.version} + + + * + * + + + + + org.apache.hop + hop-ui + ${hop.version} + + + * + * + + + + + com.google.guava + guava + 30.1.1-jre + + + com.googlecode.json-simple + json-simple + 1.1.1 + + + commons-lang + commons-lang + 2.6 + + + org.eclipse.platform + org.eclipse.swt.gtk.linux.x86_64 + 3.114.0 + + + org.apache.httpcomponents + httpcore + 4.4.16 + + + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPost.java b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPost.java new file mode 100644 index 00000000000..ba590cd0ca8 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPost.java @@ -0,0 +1,589 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.utils.transforms.grafana; + +import com.google.common.annotations.VisibleForTesting; +import org.apache.commons.lang.StringUtils; +import org.apache.hop.core.Const; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.exception.HopTransformException; +import org.apache.hop.core.row.RowDataUtil; +import org.apache.hop.core.util.HttpClientManager; +import org.apache.hop.core.util.StringUtil; +import org.apache.hop.core.util.Utils; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.transform.BaseTransform; +import org.apache.hop.pipeline.transform.ITransform; +import org.apache.hop.pipeline.transform.TransformMeta; +import org.apache.http.*; +import org.apache.http.client.AuthCache; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.InputStreamEntity; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.json.simple.JSONObject; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URLEncoder; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.apache.plc4x.hop.utils.transforms.grafana.GrafanaPostMeta.DEFAULT_ENCODING; + +/** Make a HTTP Post call */ +public class GrafanaPost extends BaseTransform implements ITransform { + + private static final Class PKG = GrafanaPostMeta.class; // For Translator + + private static final String CONTENT_TYPE = "Content-type"; + private static final String CONTENT_TYPE_TEXT_XML = "text/xml"; + private static final String PKG_HEADER_VALUE = "HTTPPOST.Log.HeaderValue"; + private static final String PKG_ERROR_FINDING_FIELD = "HTTPPOST.Log.ErrorFindingField"; + + public GrafanaPost( + TransformMeta transformMeta, + GrafanaPostMeta meta, + GrafanaPostData data, + int copyNr, + PipelineMeta pipelineMeta, + Pipeline pipeline) { + super(transformMeta, meta, data, copyNr, pipelineMeta, pipeline); + } + + private Object[] callHttpPOST(Object[] rowData) throws HopException { + HttpClientManager.HttpClientBuilderFacade clientBuilder = + HttpClientManager.getInstance().createBuilder(); + + if (data.realConnectionTimeout > -1) { + clientBuilder.setConnectionTimeout(data.realConnectionTimeout); + } + if (data.realSocketTimeout > -1) { + clientBuilder.setSocketTimeout(data.realSocketTimeout); + } + if (StringUtils.isNotBlank(data.realHttpLogin)) { + clientBuilder.setCredentials(data.realHttpLogin, data.realHttpPassword); + } + if (StringUtils.isNotBlank(data.realProxyHost)) { + clientBuilder.setProxy(data.realProxyHost, data.realProxyPort); + } + + CloseableHttpClient httpClient = clientBuilder.build(); + + // get dynamic url ? + if (meta.isUrlInField()) { + data.realUrl = data.inputRowMeta.getString(rowData, data.indexOfUrlField); + } + // Prepare HTTP POST + FileInputStream fis = null; + try { + if (isDetailed()) { + logDetailed(BaseMessages.getString(PKG, "HTTPPOST.Log.ConnectingToURL", data.realUrl)); + } + URIBuilder uriBuilder = new URIBuilder(data.realUrl); + org.apache.http.client.methods.HttpPost post = + new org.apache.http.client.methods.HttpPost(uriBuilder.build()); + + // Specify content type and encoding + // If content encoding is not explicitly specified + // ISO-8859-1 is assumed by the POSTMethod + if (!data.contentTypeHeaderOverwrite) { // can be overwritten now + if (Utils.isEmpty(data.realEncoding)) { + post.setHeader(CONTENT_TYPE, CONTENT_TYPE_TEXT_XML); + if (isDebug()) { + logDebug( + BaseMessages.getString(PKG, PKG_HEADER_VALUE, CONTENT_TYPE, CONTENT_TYPE_TEXT_XML)); + } + } else { + post.setHeader(CONTENT_TYPE, CONTENT_TYPE_TEXT_XML + "; " + data.realEncoding); + if (isDebug()) { + logDebug( + BaseMessages.getString( + PKG, + PKG_HEADER_VALUE, + CONTENT_TYPE, + CONTENT_TYPE_TEXT_XML + "; " + data.realEncoding)); + } + } + } + + // HEADER PARAMETERS + if (data.useHeaderParameters) { + // set header parameters that we want to send + for (int i = 0; i < data.header_parameters_nrs.length; i++) { + post.addHeader( + data.headerParameters[i].getName(), + data.inputRowMeta.getString(rowData, data.header_parameters_nrs[i])); + if (isDebug()) { + logDebug( + BaseMessages.getString( + PKG, + PKG_HEADER_VALUE, + data.headerParameters[i].getName(), + data.inputRowMeta.getString(rowData, data.header_parameters_nrs[i]))); + } + } + } + + // BODY PARAMETERS + if (data.useBodyParameters) { + // set body parameters that we want to send + for (int i = 0; i < data.body_parameters_nrs.length; i++) { + String bodyParameterName = data.bodyParameters[i].getName(); + String bodyParameterValue = + data.inputRowMeta.getString(rowData, data.body_parameters_nrs[i]); + data.bodyParameters[i] = new BasicNameValuePair(bodyParameterName, bodyParameterValue); + if (isDebug()) { + logDebug( + BaseMessages.getString( + PKG, "HTTPPOST.Log.BodyValue", bodyParameterName, bodyParameterValue)); + } + } + String bodyParams = getRequestBodyParamsAsStr(data.bodyParameters, data.realEncoding); + post.setEntity( + (new StringEntity(bodyParams, ContentType.TEXT_XML.withCharset("US-ASCII")))); + } + + // QUERY PARAMETERS + if (data.useQueryParameters) { + for (int i = 0; i < data.query_parameters_nrs.length; i++) { + String queryParameterName = data.queryParameters[i].getName(); + String queryParameterValue = + data.inputRowMeta.getString(rowData, data.query_parameters_nrs[i]); + data.queryParameters[i] = new BasicNameValuePair(queryParameterName, queryParameterValue); + if (isDebug()) { + logDebug( + BaseMessages.getString( + PKG, "HTTPPOST.Log.QueryValue", queryParameterName, queryParameterValue)); + } + } + post.setEntity(new UrlEncodedFormEntity(Arrays.asList(data.queryParameters))); + } + + // Set request entity? + if (data.indexOfRequestEntity >= 0) { + String tmp = data.inputRowMeta.getString(rowData, data.indexOfRequestEntity); + // Request content will be retrieved directly + // from the input stream + // Per default, the request content needs to be buffered + // in order to determine its length. + // Request body buffering can be avoided when + // content length is explicitly specified + + if (meta.isPostAFile()) { + File input = new File(tmp); + fis = new FileInputStream(input); + post.setEntity(new InputStreamEntity(fis, input.length())); + } else { + byte[] bytes; + if ((data.realEncoding != null) && (data.realEncoding.length() > 0)) { + bytes = tmp.getBytes(data.realEncoding); + } else { + bytes = tmp.getBytes(); + } + post.setEntity(new ByteArrayEntity(bytes)); + } + } + + // Execute request + Object[] newRow = null; + if (rowData != null) { + newRow = rowData.clone(); + } + CloseableHttpResponse httpResponse = null; + try { + // used for calculating the responseTime + long startTime = System.currentTimeMillis(); + + // Execute the POST method + if (StringUtils.isNotBlank(data.realProxyHost)) { + HttpHost target = new HttpHost(data.realProxyHost, data.realProxyPort, "http"); + // Create AuthCache instance + AuthCache authCache = new BasicAuthCache(); + // Generate BASIC scheme object and add it to the local + // auth cache + BasicScheme basicAuth = new BasicScheme(); + authCache.put(target, basicAuth); + // Add AuthCache to the execution context + HttpClientContext localContext = HttpClientContext.create(); + localContext.setAuthCache(authCache); + httpResponse = httpClient.execute(target, post, localContext); + } else { + httpResponse = httpClient.execute(post); + } + int statusCode = requestStatusCode(httpResponse); + + // calculate the responseTime + long responseTime = System.currentTimeMillis() - startTime; + + if (isDetailed()) { + logDetailed( + BaseMessages.getString(PKG, "HTTPPOST.Log.ResponseTime", responseTime, data.realUrl)); + } + + // Display status code + if (isDebug()) { + logDebug( + BaseMessages.getString(PKG, "HTTPPOST.Log.ResponseCode", String.valueOf(statusCode))); + } + + String body; + String headerString = ""; + switch (statusCode) { + case HttpURLConnection.HTTP_UNAUTHORIZED: + throw new HopTransformException( + BaseMessages.getString(PKG, "HTTPPOST.Exception.Authentication", data.realUrl)); + case -1: + throw new HopTransformException( + BaseMessages.getString(PKG, "HTTPPOST.Exception.IllegalStatusCode", data.realUrl)); + case HttpURLConnection.HTTP_NO_CONTENT: + body = ""; + break; + default: + HttpEntity entity = httpResponse.getEntity(); + if (entity != null) { + body = EntityUtils.toString(entity); + } else { + body = ""; + } + Header[] headers = searchForHeaders(httpResponse); + // Use request encoding if specified in component to avoid strange response encodings + + JSONObject json = new JSONObject(); + for (Header header : headers) { + Object previousValue = json.get(header.getName()); + if (previousValue == null) { + json.put(header.getName(), header.getValue()); + } else if (previousValue instanceof List) { + List list = (List) previousValue; + list.add(header.getValue()); + } else { + ArrayList list = new ArrayList<>(); + list.add((String) previousValue); + list.add(header.getValue()); + json.put(header.getName(), list); + } + } + headerString = json.toJSONString(); + } + + if (isDebug()) { + logDebug(BaseMessages.getString(PKG, "HTTPPOST.Log.ResponseBody", body)); + } + + int returnFieldsOffset = data.inputRowMeta.size(); + if (!Utils.isEmpty(meta.getHttpPostResultField().get(0).getName())) { + newRow = RowDataUtil.addValueData(newRow, returnFieldsOffset, body); + returnFieldsOffset++; + } + + if (!Utils.isEmpty(meta.getHttpPostResultField().get(0).getCode())) { + newRow = RowDataUtil.addValueData(newRow, returnFieldsOffset, Long.valueOf(statusCode)); + returnFieldsOffset++; + } + if (!Utils.isEmpty(meta.getHttpPostResultField().get(0).getResponseTimeFieldName())) { + newRow = RowDataUtil.addValueData(newRow, returnFieldsOffset, Long.valueOf(responseTime)); + returnFieldsOffset++; + } + if (!Utils.isEmpty(meta.getHttpPostResultField().get(0).getResponseHeaderFieldName())) { + newRow = RowDataUtil.addValueData(newRow, returnFieldsOffset, headerString); + } + } finally { + // Release current connection to the connection pool once you are done + post.releaseConnection(); + if (httpResponse != null) { + httpResponse.close(); + } + } + return newRow; + } catch (UnknownHostException uhe) { + throw new HopException( + BaseMessages.getString(PKG, "HTTPPOST.Error.UnknownHostException", uhe.getMessage())); + } catch (Exception e) { + throw new HopException( + BaseMessages.getString(PKG, "HTTPPOST.Error.CanNotReadURL", data.realUrl), e); + + } finally { + if (fis != null) { + BaseTransform.closeQuietly(fis); + } + } + } + + protected int requestStatusCode(HttpResponse httpResponse) { + return httpResponse.getStatusLine().getStatusCode(); + } + + protected InputStreamReader openStream(String encoding, HttpResponse httpResponse) + throws Exception { + if (!Utils.isEmpty(encoding)) { + return new InputStreamReader(httpResponse.getEntity().getContent(), encoding); + } else { + return new InputStreamReader(httpResponse.getEntity().getContent()); + } + } + + protected Header[] searchForHeaders(HttpResponse response) { + return response.getAllHeaders(); + } + + @Override + public boolean processRow() throws HopException { + + Object[] r = getRow(); // Get row from input rowset & set row busy! + if (r == null) { // no more input to be expected... + setOutputDone(); + return false; + } + if (first) { + first = false; + data.inputRowMeta = getInputRowMeta(); + data.outputRowMeta = getInputRowMeta().clone(); + meta.getFields(data.outputRowMeta, getTransformName(), null, null, this, metadataProvider); + + if (meta.isUrlInField()) { + if (Utils.isEmpty(meta.getUrlField())) { + logError(BaseMessages.getString(PKG, "HTTPPOST.Log.NoField")); + throw new HopException(BaseMessages.getString(PKG, "HTTPPOST.Log.NoField")); + } + + // cache the position of the field + if (data.indexOfUrlField < 0) { + String realUrlfieldName = resolve(meta.getUrlField()); + data.indexOfUrlField = data.inputRowMeta.indexOfValue((realUrlfieldName)); + if (data.indexOfUrlField < 0) { + // The field is unreachable ! + logError(BaseMessages.getString(PKG, PKG_ERROR_FINDING_FIELD, realUrlfieldName)); + throw new HopException( + BaseMessages.getString( + PKG, "HTTPPOST.Exception.ErrorFindingField", realUrlfieldName)); + } + } + } else { + data.realUrl = resolve(meta.getUrl()); + } + // set body parameters + int nrargs = meta.getLookupfield().get(0).getArgumentField().size(); + if (nrargs > 0) { + data.useBodyParameters = false; + data.useHeaderParameters = false; + data.contentTypeHeaderOverwrite = false; + int nrheader = 0; + int nrbody = 0; + for (int i = 0; i < nrargs; i++) { // split into body / header + if (meta.getLookupfield().get(0).getArgumentField().get(i).isHeader()) { + data.useHeaderParameters = true; // at least one header parameter + nrheader++; + } else { + data.useBodyParameters = true; // at least one body parameter + nrbody++; + } + } + data.header_parameters_nrs = new int[nrheader]; + data.headerParameters = new NameValuePair[nrheader]; + data.body_parameters_nrs = new int[nrbody]; + data.bodyParameters = new NameValuePair[nrbody]; + int posHeader = 0; + int posBody = 0; + for (int i = 0; i < nrargs; i++) { + int fieldIndex = + data.inputRowMeta.indexOfValue( + meta.getLookupfield().get(0).getArgumentField().get(i).getName()); + if (fieldIndex < 0) { + logError( + BaseMessages.getString(PKG, PKG_ERROR_FINDING_FIELD) + + meta.getLookupfield().get(0).getArgumentField().get(i).getName() + + "]"); + throw new HopTransformException( + BaseMessages.getString( + PKG, + "HTTPPOST.Exception.CouldnotFindField", + meta.getLookupfield().get(0).getArgumentField().get(i).getName())); + } + if (meta.getLookupfield().get(0).getArgumentField().get(i).isHeader()) { + data.header_parameters_nrs[posHeader] = fieldIndex; + data.headerParameters[posHeader] = + new BasicNameValuePair( + resolve(meta.getLookupfield().get(0).getArgumentField().get(i).getParameter()), + data.outputRowMeta.getString(r, data.header_parameters_nrs[posHeader])); + posHeader++; + if (CONTENT_TYPE.equalsIgnoreCase( + meta.getLookupfield().get(0).getArgumentField().get(i).getParameter())) { + data.contentTypeHeaderOverwrite = true; // Content-type will be overwritten + } + } else { + data.body_parameters_nrs[posBody] = fieldIndex; + data.bodyParameters[posBody] = + new BasicNameValuePair( + resolve(meta.getLookupfield().get(0).getArgumentField().get(i).getParameter()), + data.outputRowMeta.getString(r, data.body_parameters_nrs[posBody])); + posBody++; + } + } + } + // set query parameters + int nrQuery = meta.getLookupfield().get(0).getQueryField().size(); + if (nrQuery > 0) { + data.useQueryParameters = true; + data.query_parameters_nrs = new int[nrQuery]; + data.queryParameters = new NameValuePair[nrQuery]; + for (int i = 0; i < nrQuery; i++) { + data.query_parameters_nrs[i] = + data.inputRowMeta.indexOfValue( + meta.getLookupfield().get(0).getQueryField().get(i).getName()); + if (data.query_parameters_nrs[i] < 0) { + logError( + BaseMessages.getString(PKG, PKG_ERROR_FINDING_FIELD) + + meta.getLookupfield().get(0).getQueryField().get(i).getName() + + "]"); + throw new HopTransformException( + BaseMessages.getString( + PKG, + "HTTPPOST.Exception.CouldnotFindField", + meta.getLookupfield().get(0).getQueryField().get(i).getName())); + } + data.queryParameters[i] = + new BasicNameValuePair( + resolve(meta.getLookupfield().get(0).getQueryField().get(i).getParameter()), + data.outputRowMeta.getString(r, data.query_parameters_nrs[i])); + } + } + // set request entity? + if (!Utils.isEmpty(meta.getRequestEntity())) { + data.indexOfRequestEntity = + data.inputRowMeta.indexOfValue(resolve(meta.getRequestEntity())); + if (data.indexOfRequestEntity < 0) { + throw new HopTransformException( + BaseMessages.getString( + PKG, + "HTTPPOST.Exception.CouldnotFindRequestEntityField", + meta.getRequestEntity())); + } + } + data.realEncoding = resolve(meta.getEncoding()); + } // end if first + + try { + Object[] outputRowData = callHttpPOST(r); + putRow(data.outputRowMeta, outputRowData); // copy row to output rowset(s) + + if (checkFeedback(getLinesRead()) && isDetailed()) { + logDetailed(BaseMessages.getString(PKG, "HTTPPOST.LineNumber") + getLinesRead()); + } + } catch (HopException e) { + boolean sendToErrorRow = false; + String errorMessage = null; + + if (getTransformMeta().isDoingErrorHandling()) { + sendToErrorRow = true; + errorMessage = e.toString(); + } else { + logError(BaseMessages.getString(PKG, "HTTPPOST.ErrorInTransformRunning") + e.getMessage()); + setErrors(1); + logError(Const.getStackTracker(e)); + stopAll(); + setOutputDone(); // signal end to receiver(s) + return false; + } + + if (sendToErrorRow) { + // Simply add this row to the error row + putError(getInputRowMeta(), r, 1, errorMessage, null, "HTTPPOST001"); + } + } + + return true; + } + + @VisibleForTesting + String getRequestBodyParamsAsStr(NameValuePair[] pairs, String charset) throws HopException { + StringBuilder buf = new StringBuilder(); + try { + for (int i = 0; i < pairs.length; ++i) { + NameValuePair pair = pairs[i]; + if (pair.getName() != null) { + if (i > 0) { + buf.append("&"); + } + System.out.println("Caracter set: " + charset); + + if (!charset.matches("US-ASCII")) { + buf.append( + URLEncoder.encode( + pair.getName(), !StringUtil.isEmpty(charset) ? charset : DEFAULT_ENCODING)); + + if (!StringUtil.isEmpty(pair.getName())) + buf.append("="); + + if (pair.getValue() != null) { + buf.append( + URLEncoder.encode( + pair.getValue(), !StringUtil.isEmpty(charset) ? charset : DEFAULT_ENCODING)); + } + } else { + buf.append(pair.getName()); + + if (!StringUtil.isEmpty(pair.getName())) + buf.append("="); + + buf.append(pair.getValue()); + } + } + } + return buf.toString(); + } catch (UnsupportedEncodingException e) { + throw new HopException(e.getMessage(), e.getCause()); + } + } + + @Override + public boolean init() { + + if (super.init()) { + // get authentication settings once + data.realProxyHost = resolve(meta.getProxyHost()); + data.realProxyPort = Const.toInt(resolve(meta.getProxyPort()), 8080); + data.realHttpLogin = resolve(meta.getHttpLogin()); + data.realHttpPassword = Utils.resolvePassword(variables, meta.getHttpPassword()); + + data.realSocketTimeout = Const.toInt(resolve(meta.getSocketTimeout()), -1); + data.realConnectionTimeout = Const.toInt(resolve(meta.getSocketTimeout()), -1); + data.realcloseIdleConnectionsTime = + Const.toInt(resolve(meta.getCloseIdleConnectionsTime()), -1); + + return true; + } + return false; + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostArgumentField.java b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostArgumentField.java new file mode 100644 index 00000000000..29af6b04749 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostArgumentField.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.utils.transforms.grafana; + +import org.apache.hop.metadata.api.HopMetadataProperty; + +public class GrafanaPostArgumentField { + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.ArgumentFieldName") + private String name; + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.ArgumentFieldParameter") + private String parameter; + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.ArgumentFieldHeader") + private boolean header; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getParameter() { + return parameter; + } + + public void setParameter(String parameter) { + this.parameter = parameter; + } + + public boolean isHeader() { + return header; + } + + public void setHeader(boolean header) { + this.header = header; + } + + public GrafanaPostArgumentField(String name, String parameter, boolean header) { + this.name = name; + this.parameter = parameter; + this.header = header; + } + + public GrafanaPostArgumentField(GrafanaPostArgumentField httpPostArgumentField) { + this.name = httpPostArgumentField.name; + this.parameter = httpPostArgumentField.parameter; + this.header = httpPostArgumentField.header; + } + + public GrafanaPostArgumentField() {} +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostData.java b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostData.java new file mode 100644 index 00000000000..106ae9f0d28 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostData.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.utils.transforms.grafana; + +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.pipeline.transform.BaseTransformData; +import org.apache.hop.pipeline.transform.ITransformData; +import org.apache.http.NameValuePair; + +public class GrafanaPostData extends BaseTransformData implements ITransformData { + public IRowMeta outputRowMeta; + public IRowMeta inputRowMeta; + public String realEncoding; + public int[] header_parameters_nrs; + public int[] body_parameters_nrs; + public int[] query_parameters_nrs; + public int indexOfUrlField; + public String realUrl; + public NameValuePair[] headerParameters; + public NameValuePair[] bodyParameters; + public NameValuePair[] queryParameters; + public boolean useHeaderParameters; + public boolean contentTypeHeaderOverwrite; + public boolean useBodyParameters; + public boolean useQueryParameters; + public int indexOfRequestEntity; + + public String realProxyHost; + public int realProxyPort; + public String realHttpLogin; + public String realHttpPassword; + + public int realSocketTimeout; + public int realConnectionTimeout; + public int realcloseIdleConnectionsTime; + + public GrafanaPostData() { + super(); + indexOfUrlField = -1; + useHeaderParameters = false; + contentTypeHeaderOverwrite = false; + useBodyParameters = false; + useQueryParameters = false; + indexOfRequestEntity = -1; + realEncoding = null; + realProxyHost = null; + realProxyPort = 8080; + realHttpLogin = null; + realHttpPassword = null; + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostDialog.java b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostDialog.java new file mode 100644 index 00000000000..6c8cd720457 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostDialog.java @@ -0,0 +1,1098 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.utils.transforms.grafana; + +import org.apache.hop.core.Const; +import org.apache.hop.core.Props; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.util.Utils; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.transform.BaseTransformMeta; +import org.apache.hop.pipeline.transform.ITransformDialog; +import org.apache.hop.pipeline.transform.TransformMeta; +import org.apache.hop.ui.core.dialog.BaseDialog; +import org.apache.hop.ui.core.dialog.ErrorDialog; +import org.apache.hop.ui.core.widget.*; +import org.apache.hop.ui.pipeline.transform.BaseTransformDialog; +import org.apache.hop.ui.pipeline.transform.ComponentSelectionListener; +import org.apache.hop.ui.pipeline.transform.ITableItemInsertListener; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.events.*; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.*; + +import java.nio.charset.Charset; +import java.util.List; +import java.util.*; + +public class GrafanaPostDialog extends BaseTransformDialog implements ITransformDialog { + private static final Class PKG = GrafanaPostMeta.class; // For Translator + + private static final String[] YES_NO_COMBO = + new String[] { + BaseMessages.getString(PKG, "System.Combo.No"), + BaseMessages.getString(PKG, "System.Combo.Yes") + }; + private static final String YES = BaseMessages.getString(PKG, "System.Combo.Yes"); + private static final String NO = BaseMessages.getString(PKG, "System.Combo.No"); + + private Label wlUrl; + private TextVar wUrl; + + private TextVar wResult; + + private TextVar wResultCode; + + private TextVar wResponseTime; + private TextVar wResponseHeader; + + private TableView wFields; + + private TableView wQuery; + + private Button wUrlInField; + + private Label wlUrlField; + private ComboVar wUrlField; + + private ComboVar wRequestEntity; + + private TextVar wHttpLogin; + + private TextVar wHttpPassword; + + private TextVar wProxyHost; + + private TextVar wProxyPort; + + private final GrafanaPostMeta input; + + private final Map inputFields; + + private ColumnInfo[] colinf; + private ColumnInfo[] colinfquery; + + private String[] fieldNames; + + private boolean gotPreviousFields = false; + + private ComboVar wEncoding; + + private Button wPostAFile; + + private boolean gotEncodings = false; + + private TextVar wConnectionTimeOut; + + private TextVar wSocketTimeOut; + + private TextVar wCloseIdleConnectionsTime; + + public GrafanaPostDialog( + Shell parent, IVariables variables, Object in, PipelineMeta pipelineMeta, String sname) { + super(parent, variables, (BaseTransformMeta) in, pipelineMeta, sname); + input = (GrafanaPostMeta) in; + inputFields = new HashMap<>(); + } + + @Override + public String open() { + Shell parent = getParent(); + + shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX | SWT.MIN); + props.setLook(shell); + setShellImage(shell, input); + + ModifyListener lsMod = e -> input.setChanged(); + + changed = input.hasChanged(); + + FormLayout formLayout = new FormLayout(); + formLayout.marginWidth = Const.FORM_MARGIN; + formLayout.marginHeight = Const.FORM_MARGIN; + + shell.setLayout(formLayout); + shell.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.Shell.Title")); + + int middle = props.getMiddlePct(); + int margin = props.getMargin(); + + // THE BUTTONS + wOk = new Button(shell, SWT.PUSH); + wOk.setText(BaseMessages.getString(PKG, "System.Button.OK")); + wOk.addListener(SWT.Selection, e -> ok()); + wCancel = new Button(shell, SWT.PUSH); + wCancel.setText(BaseMessages.getString(PKG, "System.Button.Cancel")); + wCancel.addListener(SWT.Selection, e -> cancel()); + setButtonPositions(new Button[] {wOk, wCancel}, margin, null); + + // TransformName line + wlTransformName = new Label(shell, SWT.RIGHT); + wlTransformName.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.TransformName.Label")); + props.setLook(wlTransformName); + fdlTransformName = new FormData(); + fdlTransformName.left = new FormAttachment(0, 0); + fdlTransformName.right = new FormAttachment(middle, -margin); + fdlTransformName.top = new FormAttachment(0, margin); + wlTransformName.setLayoutData(fdlTransformName); + wTransformName = new Text(shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + wTransformName.setText(transformName); + props.setLook(wTransformName); + wTransformName.addModifyListener(lsMod); + fdTransformName = new FormData(); + fdTransformName.left = new FormAttachment(middle, 0); + fdTransformName.top = new FormAttachment(0, margin); + fdTransformName.right = new FormAttachment(100, 0); + wTransformName.setLayoutData(fdTransformName); + + CTabFolder wTabFolder = new CTabFolder(shell, SWT.BORDER); + props.setLook(wTabFolder, Props.WIDGET_STYLE_TAB); + + // //////////////////////// + // START OF GENERAL TAB /// + // //////////////////////// + CTabItem wGeneralTab = new CTabItem(wTabFolder, SWT.NONE); + wGeneralTab.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.GeneralTab.Title")); + + Composite wGeneralComp = new Composite(wTabFolder, SWT.NONE); + props.setLook(wGeneralComp); + + FormLayout fileLayout = new FormLayout(); + fileLayout.marginWidth = 3; + fileLayout.marginHeight = 3; + wGeneralComp.setLayout(fileLayout); + + // //////////////////////// + // START Settings GROUP + + Group gSettings = new Group(wGeneralComp, SWT.SHADOW_ETCHED_IN); + gSettings.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.SettingsGroup.Label")); + FormLayout settingsLayout = new FormLayout(); + settingsLayout.marginWidth = 3; + settingsLayout.marginHeight = 3; + gSettings.setLayout(settingsLayout); + props.setLook(gSettings); + + wlUrl = new Label(gSettings, SWT.RIGHT); + wlUrl.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.URL.Label")); + props.setLook(wlUrl); + FormData fdlUrl = new FormData(); + fdlUrl.left = new FormAttachment(0, 0); + fdlUrl.right = new FormAttachment(middle, -margin); + fdlUrl.top = new FormAttachment(wTransformName, margin); + wlUrl.setLayoutData(fdlUrl); + + wUrl = new TextVar(variables, gSettings, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wUrl); + wUrl.addModifyListener(lsMod); + FormData fdUrl = new FormData(); + fdUrl.left = new FormAttachment(middle, 0); + fdUrl.top = new FormAttachment(wTransformName, margin); + fdUrl.right = new FormAttachment(100, 0); + wUrl.setLayoutData(fdUrl); + + // UrlInField line + Label wlUrlInField = new Label(gSettings, SWT.RIGHT); + wlUrlInField.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.UrlInField.Label")); + props.setLook(wlUrlInField); + FormData fdlUrlInField = new FormData(); + fdlUrlInField.left = new FormAttachment(0, 0); + fdlUrlInField.top = new FormAttachment(wUrl, margin); + fdlUrlInField.right = new FormAttachment(middle, -margin); + wlUrlInField.setLayoutData(fdlUrlInField); + wUrlInField = new Button(gSettings, SWT.CHECK); + props.setLook(wUrlInField); + FormData fdUrlInField = new FormData(); + fdUrlInField.left = new FormAttachment(middle, 0); + fdUrlInField.top = new FormAttachment(wlUrlInField, 0, SWT.CENTER); + fdUrlInField.right = new FormAttachment(100, 0); + wUrlInField.setLayoutData(fdUrlInField); + wUrlInField.addSelectionListener( + new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + input.setChanged(); + activeUrlInfield(); + } + }); + + // UrlField Line + wlUrlField = new Label(gSettings, SWT.RIGHT); + wlUrlField.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.UrlField.Label")); + props.setLook(wlUrlField); + FormData fdlUrlField = new FormData(); + fdlUrlField.left = new FormAttachment(0, 0); + fdlUrlField.right = new FormAttachment(middle, -margin); + fdlUrlField.top = new FormAttachment(wUrlInField, margin); + wlUrlField.setLayoutData(fdlUrlField); + + wUrlField = new ComboVar(variables, gSettings, SWT.BORDER | SWT.READ_ONLY); + wUrlField.setEditable(true); + props.setLook(wUrlField); + wUrlField.addModifyListener(lsMod); + FormData fdUrlField = new FormData(); + fdUrlField.left = new FormAttachment(middle, 0); + fdUrlField.top = new FormAttachment(wUrlInField, margin); + fdUrlField.right = new FormAttachment(100, -margin); + wUrlField.setLayoutData(fdUrlField); + wUrlField.addFocusListener( + new FocusListener() { + @Override + public void focusLost(FocusEvent e) { + // Disable focuslost event + } + + @Override + public void focusGained(FocusEvent e) { + Cursor busy = new Cursor(shell.getDisplay(), SWT.CURSOR_WAIT); + shell.setCursor(busy); + setStreamFields(); + shell.setCursor(null); + busy.dispose(); + } + }); + + Label wlEncoding = new Label(gSettings, SWT.RIGHT); + wlEncoding.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.Encoding.Label")); + props.setLook(wlEncoding); + FormData fdlEncoding = new FormData(); + fdlEncoding.left = new FormAttachment(0, 0); + fdlEncoding.top = new FormAttachment(wUrlField, margin); + fdlEncoding.right = new FormAttachment(middle, -margin); + wlEncoding.setLayoutData(fdlEncoding); + wEncoding = new ComboVar(variables, gSettings, SWT.BORDER | SWT.READ_ONLY); + wEncoding.setEditable(true); + props.setLook(wEncoding); + wEncoding.addModifyListener(lsMod); + FormData fdEncoding = new FormData(); + fdEncoding.left = new FormAttachment(middle, 0); + fdEncoding.top = new FormAttachment(wUrlField, margin); + fdEncoding.right = new FormAttachment(100, -margin); + wEncoding.setLayoutData(fdEncoding); + wEncoding.addFocusListener( + new FocusListener() { + @Override + public void focusLost(FocusEvent e) { + // Disable focuslost event + } + + @Override + public void focusGained(FocusEvent e) { + Cursor busy = new Cursor(shell.getDisplay(), SWT.CURSOR_WAIT); + shell.setCursor(busy); + setEncodings(); + shell.setCursor(null); + busy.dispose(); + } + }); + + // requestEntity Line + Label wlRequestEntity = new Label(gSettings, SWT.RIGHT); + wlRequestEntity.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.requestEntity.Label")); + props.setLook(wlRequestEntity); + FormData fdlRequestEntity = new FormData(); + fdlRequestEntity.left = new FormAttachment(0, 0); + fdlRequestEntity.right = new FormAttachment(middle, -margin); + fdlRequestEntity.top = new FormAttachment(wEncoding, margin); + wlRequestEntity.setLayoutData(fdlRequestEntity); + + wRequestEntity = new ComboVar(variables, gSettings, SWT.BORDER | SWT.READ_ONLY); + wRequestEntity.setEditable(true); + props.setLook(wRequestEntity); + wRequestEntity.addModifyListener(lsMod); + FormData fdRequestEntity = new FormData(); + fdRequestEntity.left = new FormAttachment(middle, 0); + fdRequestEntity.top = new FormAttachment(wEncoding, margin); + fdRequestEntity.right = new FormAttachment(100, -margin); + wRequestEntity.setLayoutData(fdRequestEntity); + wRequestEntity.addFocusListener( + new FocusListener() { + @Override + public void focusLost(FocusEvent e) { + // Disable focuslost event + } + + @Override + public void focusGained(FocusEvent e) { + Cursor busy = new Cursor(shell.getDisplay(), SWT.CURSOR_WAIT); + shell.setCursor(busy); + setStreamFields(); + shell.setCursor(null); + busy.dispose(); + } + }); + + // Post file? + Label wlPostAFile = new Label(gSettings, SWT.RIGHT); + wlPostAFile.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.postAFile.Label")); + props.setLook(wlPostAFile); + FormData fdlPostAFile = new FormData(); + fdlPostAFile.left = new FormAttachment(0, 0); + fdlPostAFile.right = new FormAttachment(middle, -margin); + fdlPostAFile.top = new FormAttachment(wRequestEntity, margin); + wlPostAFile.setLayoutData(fdlPostAFile); + wPostAFile = new Button(gSettings, SWT.CHECK); + wPostAFile.setToolTipText(BaseMessages.getString(PKG, "HTTPPOSTDialog.postAFile.Tooltip")); + props.setLook(wPostAFile); + FormData fdPostAFile = new FormData(); + fdPostAFile.left = new FormAttachment(middle, 0); + fdPostAFile.top = new FormAttachment(wlPostAFile, 0, SWT.CENTER); + fdPostAFile.right = new FormAttachment(100, 0); + wPostAFile.setLayoutData(fdPostAFile); + wPostAFile.addSelectionListener(new ComponentSelectionListener(input)); + + Label wlConnectionTimeOut = new Label(gSettings, SWT.RIGHT); + wlConnectionTimeOut.setText( + BaseMessages.getString(PKG, "HTTPPOSTDialog.ConnectionTimeOut.Label")); + props.setLook(wlConnectionTimeOut); + FormData fdlConnectionTimeOut = new FormData(); + fdlConnectionTimeOut.top = new FormAttachment(wPostAFile, margin); + fdlConnectionTimeOut.left = new FormAttachment(0, 0); + fdlConnectionTimeOut.right = new FormAttachment(middle, -margin); + wlConnectionTimeOut.setLayoutData(fdlConnectionTimeOut); + wConnectionTimeOut = new TextVar(variables, gSettings, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + wConnectionTimeOut.addModifyListener(lsMod); + wConnectionTimeOut.setToolTipText( + BaseMessages.getString(PKG, "HTTPPOSTDialog.ConnectionTimeOut.Tooltip")); + props.setLook(wConnectionTimeOut); + FormData fdConnectionTimeOut = new FormData(); + fdConnectionTimeOut.top = new FormAttachment(wPostAFile, margin); + fdConnectionTimeOut.left = new FormAttachment(middle, 0); + fdConnectionTimeOut.right = new FormAttachment(100, 0); + wConnectionTimeOut.setLayoutData(fdConnectionTimeOut); + + Label wlSocketTimeOut = new Label(gSettings, SWT.RIGHT); + wlSocketTimeOut.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.SocketTimeOut.Label")); + props.setLook(wlSocketTimeOut); + FormData fdlSocketTimeOut = new FormData(); + fdlSocketTimeOut.top = new FormAttachment(wConnectionTimeOut, margin); + fdlSocketTimeOut.left = new FormAttachment(0, 0); + fdlSocketTimeOut.right = new FormAttachment(middle, -margin); + wlSocketTimeOut.setLayoutData(fdlSocketTimeOut); + wSocketTimeOut = new TextVar(variables, gSettings, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + wSocketTimeOut.addModifyListener(lsMod); + wSocketTimeOut.setToolTipText( + BaseMessages.getString(PKG, "HTTPPOSTDialog.SocketTimeOut.Tooltip")); + props.setLook(wSocketTimeOut); + FormData fdSocketTimeOut = new FormData(); + fdSocketTimeOut.top = new FormAttachment(wConnectionTimeOut, margin); + fdSocketTimeOut.left = new FormAttachment(middle, 0); + fdSocketTimeOut.right = new FormAttachment(100, 0); + wSocketTimeOut.setLayoutData(fdSocketTimeOut); + + Label wlCloseIdleConnectionsTime = new Label(gSettings, SWT.RIGHT); + wlCloseIdleConnectionsTime.setText( + BaseMessages.getString(PKG, "HTTPPOSTDialog.CloseIdleConnectionsTime.Label")); + props.setLook(wlCloseIdleConnectionsTime); + FormData fdlCloseIdleConnectionsTime = new FormData(); + fdlCloseIdleConnectionsTime.top = new FormAttachment(wSocketTimeOut, margin); + fdlCloseIdleConnectionsTime.left = new FormAttachment(0, 0); + fdlCloseIdleConnectionsTime.right = new FormAttachment(middle, -margin); + wlCloseIdleConnectionsTime.setLayoutData(fdlCloseIdleConnectionsTime); + wCloseIdleConnectionsTime = + new TextVar(variables, gSettings, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + wCloseIdleConnectionsTime.addModifyListener(lsMod); + wCloseIdleConnectionsTime.setToolTipText( + BaseMessages.getString(PKG, "HTTPPOSTDialog.CloseIdleConnectionsTime.Tooltip")); + props.setLook(wCloseIdleConnectionsTime); + FormData fdCloseIdleConnectionsTime = new FormData(); + fdCloseIdleConnectionsTime.top = new FormAttachment(wSocketTimeOut, margin); + fdCloseIdleConnectionsTime.left = new FormAttachment(middle, 0); + fdCloseIdleConnectionsTime.right = new FormAttachment(100, 0); + wCloseIdleConnectionsTime.setLayoutData(fdCloseIdleConnectionsTime); + + FormData fdSettings = new FormData(); + fdSettings.left = new FormAttachment(0, 0); + fdSettings.right = new FormAttachment(100, 0); + fdSettings.top = new FormAttachment(wTransformName, margin); + gSettings.setLayoutData(fdSettings); + + // END Output Settings GROUP + // //////////////////////// + + // //////////////////////// + // START Output Fields GROUP + + Group gOutputFields = new Group(wGeneralComp, SWT.SHADOW_ETCHED_IN); + gOutputFields.setText(BaseMessages.getString(PKG, "HTTPDialog.OutputFieldsGroup.Label")); + FormLayout outputFieldsLayout = new FormLayout(); + outputFieldsLayout.marginWidth = 3; + outputFieldsLayout.marginHeight = 3; + gOutputFields.setLayout(outputFieldsLayout); + props.setLook(gOutputFields); + + // Result line... + Label wlResult = new Label(gOutputFields, SWT.RIGHT); + wlResult.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.Result.Label")); + props.setLook(wlResult); + FormData fdlResult = new FormData(); + fdlResult.left = new FormAttachment(0, 0); + fdlResult.right = new FormAttachment(middle, -margin); + fdlResult.top = new FormAttachment(wPostAFile, margin); + wlResult.setLayoutData(fdlResult); + wResult = new TextVar(variables, gOutputFields, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wResult); + wResult.addModifyListener(lsMod); + FormData fdResult = new FormData(); + fdResult.left = new FormAttachment(middle, 0); + fdResult.top = new FormAttachment(wPostAFile, margin); + fdResult.right = new FormAttachment(100, -margin); + wResult.setLayoutData(fdResult); + + // Resultcode line... + Label wlResultCode = new Label(gOutputFields, SWT.RIGHT); + wlResultCode.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.ResultCode.Label")); + props.setLook(wlResultCode); + FormData fdlResultCode = new FormData(); + fdlResultCode.left = new FormAttachment(0, 0); + fdlResultCode.right = new FormAttachment(middle, -margin); + fdlResultCode.top = new FormAttachment(wResult, margin); + wlResultCode.setLayoutData(fdlResultCode); + wResultCode = new TextVar(variables, gOutputFields, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wResultCode); + wResultCode.addModifyListener(lsMod); + FormData fdResultCode = new FormData(); + fdResultCode.left = new FormAttachment(middle, 0); + fdResultCode.top = new FormAttachment(wResult, margin); + fdResultCode.right = new FormAttachment(100, -margin); + wResultCode.setLayoutData(fdResultCode); + + // Response time line... + Label wlResponseTime = new Label(gOutputFields, SWT.RIGHT); + wlResponseTime.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.ResponseTime.Label")); + props.setLook(wlResponseTime); + FormData fdlResponseTime = new FormData(); + fdlResponseTime.left = new FormAttachment(0, 0); + fdlResponseTime.right = new FormAttachment(middle, -margin); + fdlResponseTime.top = new FormAttachment(wResultCode, margin); + wlResponseTime.setLayoutData(fdlResponseTime); + wResponseTime = new TextVar(variables, gOutputFields, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wResponseTime); + wResponseTime.addModifyListener(lsMod); + FormData fdResponseTime = new FormData(); + fdResponseTime.left = new FormAttachment(middle, 0); + fdResponseTime.top = new FormAttachment(wResultCode, margin); + fdResponseTime.right = new FormAttachment(100, 0); + wResponseTime.setLayoutData(fdResponseTime); + // Response header line... + Label wlResponseHeader = new Label(gOutputFields, SWT.RIGHT); + wlResponseHeader.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.ResponseHeader.Label")); + props.setLook(wlResponseHeader); + FormData fdlResponseHeader = new FormData(); + fdlResponseHeader.left = new FormAttachment(0, 0); + fdlResponseHeader.right = new FormAttachment(middle, -margin); + fdlResponseHeader.top = new FormAttachment(wResponseTime, margin); + wlResponseHeader.setLayoutData(fdlResponseHeader); + wResponseHeader = new TextVar(variables, gOutputFields, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wResponseHeader); + wResponseHeader.addModifyListener(lsMod); + FormData fdResponseHeader = new FormData(); + fdResponseHeader.left = new FormAttachment(middle, 0); + fdResponseHeader.top = new FormAttachment(wResponseTime, margin); + fdResponseHeader.right = new FormAttachment(100, 0); + wResponseHeader.setLayoutData(fdResponseHeader); + + FormData fdOutputFields = new FormData(); + fdOutputFields.left = new FormAttachment(0, 0); + fdOutputFields.right = new FormAttachment(100, 0); + fdOutputFields.top = new FormAttachment(gSettings, margin); + gOutputFields.setLayoutData(fdOutputFields); + + // END Output Fields GROUP + // //////////////////////// + + // //////////////////////// + // START HTTP AUTH GROUP + + Group gHttpAuth = new Group(wGeneralComp, SWT.SHADOW_ETCHED_IN); + gHttpAuth.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.HttpAuthGroup.Label")); + FormLayout httpAuthLayout = new FormLayout(); + httpAuthLayout.marginWidth = 3; + httpAuthLayout.marginHeight = 3; + gHttpAuth.setLayout(httpAuthLayout); + props.setLook(gHttpAuth); + + // HTTP Login + Label wlHttpLogin = new Label(gHttpAuth, SWT.RIGHT); + wlHttpLogin.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.HttpLogin.Label")); + props.setLook(wlHttpLogin); + FormData fdlHttpLogin = new FormData(); + fdlHttpLogin.top = new FormAttachment(0, margin); + fdlHttpLogin.left = new FormAttachment(0, 0); + fdlHttpLogin.right = new FormAttachment(middle, -margin); + wlHttpLogin.setLayoutData(fdlHttpLogin); + wHttpLogin = new TextVar(variables, gHttpAuth, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + wHttpLogin.addModifyListener(lsMod); + wHttpLogin.setToolTipText(BaseMessages.getString(PKG, "HTTPPOSTDialog.HttpLogin.Tooltip")); + props.setLook(wHttpLogin); + FormData fdHttpLogin = new FormData(); + fdHttpLogin.top = new FormAttachment(0, margin); + fdHttpLogin.left = new FormAttachment(middle, 0); + fdHttpLogin.right = new FormAttachment(100, 0); + wHttpLogin.setLayoutData(fdHttpLogin); + + // HTTP Password + Label wlHttpPassword = new Label(gHttpAuth, SWT.RIGHT); + wlHttpPassword.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.HttpPassword.Label")); + props.setLook(wlHttpPassword); + FormData fdlHttpPassword = new FormData(); + fdlHttpPassword.top = new FormAttachment(wHttpLogin, margin); + fdlHttpPassword.left = new FormAttachment(0, 0); + fdlHttpPassword.right = new FormAttachment(middle, -margin); + wlHttpPassword.setLayoutData(fdlHttpPassword); + wHttpPassword = new PasswordTextVar(variables, gHttpAuth, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + wHttpPassword.addModifyListener(lsMod); + wHttpPassword.setToolTipText( + BaseMessages.getString(PKG, "HTTPPOSTDialog.HttpPassword.Tooltip")); + props.setLook(wHttpPassword); + FormData fdHttpPassword = new FormData(); + fdHttpPassword.top = new FormAttachment(wHttpLogin, margin); + fdHttpPassword.left = new FormAttachment(middle, 0); + fdHttpPassword.right = new FormAttachment(100, 0); + wHttpPassword.setLayoutData(fdHttpPassword); + + FormData fdHttpAuth = new FormData(); + fdHttpAuth.left = new FormAttachment(0, 0); + fdHttpAuth.right = new FormAttachment(100, 0); + fdHttpAuth.top = new FormAttachment(gOutputFields, margin); + gHttpAuth.setLayoutData(fdHttpAuth); + + // END HTTP AUTH GROUP + // //////////////////////// + + // //////////////////////// + // START PROXY GROUP + + Group gProxy = new Group(wGeneralComp, SWT.SHADOW_ETCHED_IN); + gProxy.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.ProxyGroup.Label")); + FormLayout proxyLayout = new FormLayout(); + proxyLayout.marginWidth = 3; + proxyLayout.marginHeight = 3; + gProxy.setLayout(proxyLayout); + props.setLook(gProxy); + + // HTTP Login + Label wlProxyHost = new Label(gProxy, SWT.RIGHT); + wlProxyHost.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.ProxyHost.Label")); + props.setLook(wlProxyHost); + FormData fdlProxyHost = new FormData(); + fdlProxyHost.top = new FormAttachment(0, margin); + fdlProxyHost.left = new FormAttachment(0, 0); + fdlProxyHost.right = new FormAttachment(middle, -margin); + wlProxyHost.setLayoutData(fdlProxyHost); + wProxyHost = new TextVar(variables, gProxy, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + wProxyHost.addModifyListener(lsMod); + wProxyHost.setToolTipText(BaseMessages.getString(PKG, "HTTPPOSTDialog.ProxyHost.Tooltip")); + props.setLook(wProxyHost); + FormData fdProxyHost = new FormData(); + fdProxyHost.top = new FormAttachment(0, margin); + fdProxyHost.left = new FormAttachment(middle, 0); + fdProxyHost.right = new FormAttachment(100, 0); + wProxyHost.setLayoutData(fdProxyHost); + + // HTTP Password + Label wlProxyPort = new Label(gProxy, SWT.RIGHT); + wlProxyPort.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.ProxyPort.Label")); + props.setLook(wlProxyPort); + FormData fdlProxyPort = new FormData(); + fdlProxyPort.top = new FormAttachment(wProxyHost, margin); + fdlProxyPort.left = new FormAttachment(0, 0); + fdlProxyPort.right = new FormAttachment(middle, -margin); + wlProxyPort.setLayoutData(fdlProxyPort); + wProxyPort = new TextVar(variables, gProxy, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + wProxyPort.addModifyListener(lsMod); + wProxyPort.setToolTipText(BaseMessages.getString(PKG, "HTTPPOSTDialog.ProxyPort.Tooltip")); + props.setLook(wProxyPort); + FormData fdProxyPort = new FormData(); + fdProxyPort.top = new FormAttachment(wProxyHost, margin); + fdProxyPort.left = new FormAttachment(middle, 0); + fdProxyPort.right = new FormAttachment(100, 0); + wProxyPort.setLayoutData(fdProxyPort); + + FormData fdProxy = new FormData(); + fdProxy.left = new FormAttachment(0, 0); + fdProxy.right = new FormAttachment(100, 0); + fdProxy.top = new FormAttachment(gHttpAuth, margin); + gProxy.setLayoutData(fdProxy); + + // END HTTP AUTH GROUP + // //////////////////////// + + FormData fdGeneralComp = new FormData(); + fdGeneralComp.left = new FormAttachment(0, 0); + fdGeneralComp.top = new FormAttachment(wTransformName, margin); + fdGeneralComp.right = new FormAttachment(100, 0); + fdGeneralComp.bottom = new FormAttachment(100, 0); + wGeneralComp.setLayoutData(fdGeneralComp); + + wGeneralComp.layout(); + wGeneralTab.setControl(wGeneralComp); + + // /////////////////////////////////////////////////////////// + // / END OF GENERAL TAB + // /////////////////////////////////////////////////////////// + + // Additional tab... + // + CTabItem wAdditionalTab = new CTabItem(wTabFolder, SWT.NONE); + wAdditionalTab.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.FieldsTab.Title")); + + FormLayout addLayout = new FormLayout(); + addLayout.marginWidth = Const.FORM_MARGIN; + addLayout.marginHeight = Const.FORM_MARGIN; + + Composite wAdditionalComp = new Composite(wTabFolder, SWT.NONE); + wAdditionalComp.setLayout(addLayout); + props.setLook(wAdditionalComp); + + Label wlFields = new Label(wAdditionalComp, SWT.NONE); + wlFields.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.Parameters.Label")); + props.setLook(wlFields); + FormData fdlFields = new FormData(); + fdlFields.left = new FormAttachment(0, 0); + fdlFields.top = new FormAttachment(gProxy, margin); + wlFields.setLayoutData(fdlFields); + + int fieldsRows = 0; + if (input.getLookupfield().get(0).getArgumentField() != null) { + fieldsRows = input.getLookupfield().get(0).getArgumentField().size(); + } + + colinf = + new ColumnInfo[] { + new ColumnInfo( + BaseMessages.getString(PKG, "HTTPPOSTDialog.ColumnInfo.Name"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + new String[] {""}, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "HTTPPOSTDialog.ColumnInfo.Parameter"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "HTTPPOSTDialog.ColumnInfo.Header"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + YES_NO_COMBO), + }; + colinf[1].setUsingVariables(true); + wFields = + new TableView( + variables, + wAdditionalComp, + SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI, + colinf, + fieldsRows, + lsMod, + props); + + Button wGetBodyParam = new Button(wAdditionalComp, SWT.PUSH); + wGetBodyParam.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.GetFields.Button")); + FormData fdGetBodyParam = new FormData(); + fdGetBodyParam.top = new FormAttachment(wlFields, margin); + fdGetBodyParam.right = new FormAttachment(100, 0); + wGetBodyParam.setLayoutData(fdGetBodyParam); + + FormData fdFields = new FormData(); + fdFields.left = new FormAttachment(0, 0); + fdFields.top = new FormAttachment(wlFields, margin); + fdFields.right = new FormAttachment(wGetBodyParam, -margin); + fdFields.bottom = new FormAttachment(wlFields, 200); + wFields.setLayoutData(fdFields); + + Label wlQuery = new Label(wAdditionalComp, SWT.NONE); + wlQuery.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.QueryParameters.Label")); + props.setLook(wlQuery); + FormData fdlQuery = new FormData(); + fdlQuery.left = new FormAttachment(0, 0); + fdlQuery.top = new FormAttachment(wFields, margin); + wlQuery.setLayoutData(fdlQuery); + + int queryRows = 0; + if (input.getLookupfield().get(0).getQueryField() != null) { + queryRows = input.getLookupfield().get(0).getQueryField().size(); + } + + colinfquery = + new ColumnInfo[] { + new ColumnInfo( + BaseMessages.getString(PKG, "HTTPPOSTDialog.ColumnInfo.QueryName"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + new String[] {""}, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "HTTPPOSTDialog.ColumnInfo.QueryParameter"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + }; + colinfquery[1].setUsingVariables(true); + wQuery = + new TableView( + variables, + wAdditionalComp, + SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI, + colinfquery, + queryRows, + lsMod, + props); + + wGet = new Button(wAdditionalComp, SWT.PUSH); + wGet.setText(BaseMessages.getString(PKG, "HTTPPOSTDialog.GetFields.Button")); + fdGet = new FormData(); + fdGet.top = new FormAttachment(wlQuery, margin); + fdGet.right = new FormAttachment(100, 0); + wGet.setLayoutData(fdGet); + + FormData fdQuery = new FormData(); + fdQuery.left = new FormAttachment(0, 0); + fdQuery.top = new FormAttachment(wlQuery, margin); + fdQuery.right = new FormAttachment(wGet, -margin); + fdQuery.bottom = new FormAttachment(100, -margin); + wQuery.setLayoutData(fdQuery); + + // + // Search the fields in the background + // + + final Runnable runnable = + () -> { + TransformMeta transformMeta = pipelineMeta.findTransform(transformName); + if (transformMeta != null) { + try { + IRowMeta row = pipelineMeta.getPrevTransformFields(variables, transformMeta); + + // Remember these fields... + for (int i = 0; i < row.size(); i++) { + inputFields.put(row.getValueMeta(i).getName(), i); + } + + setComboBoxes(); + } catch (HopException e) { + logError(BaseMessages.getString(PKG, "System.Dialog.GetFieldsFailed.Message")); + } + } + }; + new Thread(runnable).start(); + FormData fdAdditionalComp = new FormData(); + fdAdditionalComp.left = new FormAttachment(0, 0); + fdAdditionalComp.top = new FormAttachment(wTransformName, margin); + fdAdditionalComp.right = new FormAttachment(100, 0); + fdAdditionalComp.bottom = new FormAttachment(100, 0); + wAdditionalComp.setLayoutData(fdAdditionalComp); + + wAdditionalComp.layout(); + wAdditionalTab.setControl(wAdditionalComp); + // ////// END of Additional Tab + + FormData fdTabFolder = new FormData(); + fdTabFolder.left = new FormAttachment(0, 0); + fdTabFolder.top = new FormAttachment(wTransformName, margin); + fdTabFolder.right = new FormAttachment(100, 0); + fdTabFolder.bottom = new FormAttachment(wOk, -2 * margin); + wTabFolder.setLayoutData(fdTabFolder); + + // Add listeners + wGet.addListener(SWT.Selection, e -> getQueryFields()); + wGetBodyParam.addListener(SWT.Selection, e -> get()); + + lsResize = + event -> { + Point size = shell.getSize(); + wFields.setSize(size.x - 10, size.y - 50); + wFields.table.setSize(size.x - 10, size.y - 50); + wFields.redraw(); + }; + shell.addListener(SWT.Resize, lsResize); + + wTabFolder.setSelection(0); + getData(); + activeUrlInfield(); + input.setChanged(changed); + + BaseDialog.defaultShellHandling(shell, c -> ok(), c -> cancel()); + + return transformName; + } + + protected void setComboBoxes() { + // Something was changed in the row. + // + final Map fields = new HashMap<>(); + + // Add the currentMeta fields... + fields.putAll(inputFields); + + Set keySet = fields.keySet(); + List entries = new ArrayList<>(keySet); + + fieldNames = entries.toArray(new String[entries.size()]); + + Const.sortStrings(fieldNames); + colinf[0].setComboValues(fieldNames); + colinfquery[0].setComboValues(fieldNames); + } + + private void setStreamFields() { + if (!gotPreviousFields) { + String urlfield = wUrlField.getText(); + wUrlField.removeAll(); + wUrlField.setItems(fieldNames); + if (urlfield != null) { + wUrlField.setText(urlfield); + } + + String request = wRequestEntity.getText(); + wRequestEntity.removeAll(); + wRequestEntity.setItems(fieldNames); + if (request != null) { + wRequestEntity.setText(request); + } + + gotPreviousFields = true; + } + } + + private void setEncodings() { + // Encoding of the text file: + if (!gotEncodings) { + gotEncodings = true; + + wEncoding.removeAll(); + List values = new ArrayList<>(Charset.availableCharsets().values()); + for (Charset charSet : values) { + wEncoding.add(charSet.displayName()); + } + + // Now select the default! + String defEncoding = Const.getEnvironmentVariable("file.encoding", "UTF-8"); + int idx = Const.indexOfString(defEncoding, wEncoding.getItems()); + if (idx >= 0) { + wEncoding.select(idx); + } + } + } + + private void activeUrlInfield() { + wlUrlField.setEnabled(wUrlInField.getSelection()); + wUrlField.setEnabled(wUrlInField.getSelection()); + wlUrl.setEnabled(!wUrlInField.getSelection()); + wUrl.setEnabled(!wUrlInField.getSelection()); + } + + /** Copy information from the meta-data input to the dialog fields. */ + public void getData() { + if (log.isDebug()) { + logDebug(BaseMessages.getString(PKG, "HTTPPOSTDialog.Log.GettingKeyInfo")); + } + + if (input.getLookupfield().get(0).getArgumentField() != null) { + for (int i = 0; i < input.getLookupfield().get(0).getArgumentField().size(); i++) { + TableItem item = wFields.table.getItem(i); + if (input.getLookupfield().get(0).getArgumentField().get(i).getName() != null) { + item.setText(1, input.getLookupfield().get(0).getArgumentField().get(i).getName()); + } + if (input.getLookupfield().get(0).getArgumentField().get(i).getParameter() != null) { + item.setText(2, input.getLookupfield().get(0).getArgumentField().get(i).getParameter()); + } + item.setText( + 3, (input.getLookupfield().get(0).getArgumentField().get(i).isHeader()) ? YES : NO); + } + } + if (input.getLookupfield().get(0).getQueryField() != null) { + for (int i = 0; i < input.getLookupfield().get(0).getQueryField().size(); i++) { + TableItem item = wQuery.table.getItem(i); + if (input.getLookupfield().get(0).getQueryField().get(i).getName() != null) { + item.setText(1, input.getLookupfield().get(0).getQueryField().get(i).getName()); + } + if (input.getLookupfield().get(0).getQueryField().get(i).getParameter() != null) { + item.setText(2, input.getLookupfield().get(0).getQueryField().get(i).getParameter()); + } + } + } + if (input.getUrl() != null) { + wUrl.setText(input.getUrl()); + } + wUrlInField.setSelection(input.isUrlInField()); + if (input.getUrlField() != null) { + wUrlField.setText(input.getUrlField()); + } + if (input.getRequestEntity() != null) { + wRequestEntity.setText(input.getRequestEntity()); + } + if (input.getHttpPostResultField().get(0).getName() != null) { + wResult.setText(input.getHttpPostResultField().get(0).getName()); + } + if (input.getHttpPostResultField().get(0).getCode() != null) { + wResultCode.setText(input.getHttpPostResultField().get(0).getCode()); + } + if (input.getHttpPostResultField().get(0).getResponseTimeFieldName() != null) { + wResponseTime.setText(input.getHttpPostResultField().get(0).getResponseTimeFieldName()); + } + if (input.getEncoding() != null) { + wEncoding.setText(input.getEncoding()); + } + wPostAFile.setSelection(input.isPostAFile()); + + if (input.getHttpLogin() != null) { + wHttpLogin.setText(input.getHttpLogin()); + } + if (input.getHttpPassword() != null) { + wHttpPassword.setText(input.getHttpPassword()); + } + if (input.getProxyHost() != null) { + wProxyHost.setText(input.getProxyHost()); + } + if (input.getProxyPort() != null) { + wProxyPort.setText(input.getProxyPort()); + } + if (input.getHttpPostResultField().get(0).getResponseHeaderFieldName() != null) { + wResponseHeader.setText(input.getHttpPostResultField().get(0).getResponseHeaderFieldName()); + } + + wSocketTimeOut.setText(Const.NVL(input.getSocketTimeout(), "")); + wConnectionTimeOut.setText(Const.NVL(input.getConnectionTimeout(), "")); + wCloseIdleConnectionsTime.setText(Const.NVL(input.getCloseIdleConnectionsTime(), "")); + + wFields.setRowNums(); + wFields.optWidth(true); + + wTransformName.selectAll(); + wTransformName.setFocus(); + } + + private void cancel() { + transformName = null; + input.setChanged(changed); + dispose(); + } + + private void ok() { + GrafanaPostLoookupField loookupField = new GrafanaPostLoookupField(); + if (Utils.isEmpty(wTransformName.getText())) { + return; + } + + int nrargs = wFields.nrNonEmpty(); + + if (log.isDebug()) { + logDebug( + BaseMessages.getString(PKG, "HTTPPOSTDialog.Log.FoundArguments", String.valueOf(nrargs))); + } + // CHECKSTYLE:Indentation:OFF + for (int i = 0; i < nrargs; i++) { + TableItem item = wFields.getNonEmpty(i); + GrafanaPostArgumentField argumentField = + new GrafanaPostArgumentField(item.getText(1), item.getText(2), YES.equals(item.getText(3))); + loookupField.getArgumentField().add(argumentField); + } + + int nrqueryparams = wQuery.nrNonEmpty(); + + if (log.isDebug()) { + logDebug( + BaseMessages.getString( + PKG, "HTTPPOSTDialog.Log.FoundQueryParameters", String.valueOf(nrqueryparams))); + } + // CHECKSTYLE:Indentation:OFF + for (int i = 0; i < nrqueryparams; i++) { + TableItem item = wQuery.getNonEmpty(i); + input.getLookupfield().get(0).getQueryField().clear(); + GrafanaPostQuery httpPostQuery = new GrafanaPostQuery(item.getText(1), item.getText(2)); + loookupField.getQueryField().add(httpPostQuery); + } + + List listLookupField = new ArrayList<>(); + listLookupField.add(loookupField); + input.setLookupfield(listLookupField); + + input.setUrl(wUrl.getText()); + input.setUrlField(wUrlField.getText()); + input.setRequestEntity(wRequestEntity.getText()); + input.setUrlInField(wUrlInField.getSelection()); + + GrafanaPostResultField httpPostResultField = + new GrafanaPostResultField( + wResultCode.getText(), + wResult.getText(), + wResponseTime.getText(), + wResponseHeader.getText()); + + List listHttpPostResultField = new ArrayList<>(); + listHttpPostResultField.add(httpPostResultField); + input.setHttpPostResultField(listHttpPostResultField); + + input.setEncoding(wEncoding.getText()); + input.setPostAFile(wPostAFile.getSelection()); + input.setHttpLogin(wHttpLogin.getText()); + input.setHttpPassword(wHttpPassword.getText()); + input.setProxyHost(wProxyHost.getText()); + input.setProxyPort(wProxyPort.getText()); + input.setSocketTimeout(wSocketTimeOut.getText()); + input.setConnectionTimeout(wConnectionTimeOut.getText()); + input.setCloseIdleConnectionsTime(wCloseIdleConnectionsTime.getText()); + + transformName = wTransformName.getText(); // return value + + dispose(); + } + + private void get() { + try { + IRowMeta r = pipelineMeta.getPrevTransformFields(variables, transformName); + if (r != null && !r.isEmpty()) { + ITableItemInsertListener listener = + (tableItem, v) -> { + tableItem.setText(3, NO); // default is "N" + return true; + }; + BaseTransformDialog.getFieldsFromPrevious( + r, wFields, 1, new int[] {1, 2}, null, -1, -1, listener); + } + } catch (HopException ke) { + new ErrorDialog( + shell, + BaseMessages.getString(PKG, "HTTPPOSTDialog.FailedToGetFields.DialogTitle"), + BaseMessages.getString(PKG, "HTTPPOSTDialog.FailedToGetFields.DialogMessage"), + ke); + } + } + + private void getQueryFields() { + try { + IRowMeta r = pipelineMeta.getPrevTransformFields(variables, transformName); + if (r != null && !r.isEmpty()) { + BaseTransformDialog.getFieldsFromPrevious( + r, wQuery, 1, new int[] {1, 2}, new int[] {3}, -1, -1, null); + } + } catch (HopException ke) { + new ErrorDialog( + shell, + BaseMessages.getString(PKG, "HTTPPOSTDialog.FailedToGetFields.DialogTitle"), + BaseMessages.getString(PKG, "HTTPPOSTDialog.FailedToGetFields.DialogMessage"), + ke); + } + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostLoookupField.java b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostLoookupField.java new file mode 100644 index 00000000000..71036ba13f7 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostLoookupField.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.utils.transforms.grafana; + +import org.apache.hop.metadata.api.HopMetadataProperty; + +import java.util.ArrayList; +import java.util.List; + +public class GrafanaPostLoookupField { + + @HopMetadataProperty( + key = "query", + injectionGroupDescription = "HTTPPOST.Injection.LookupQueryField") + private List queryField = new ArrayList<>(); + + @HopMetadataProperty( + key = "arg", + injectionGroupDescription = "HTTPPOST.Injection.LookupArgumentField") + private List argumentField = new ArrayList<>(); + + public List getQueryField() { + return queryField; + } + + public void setQueryField(List queryField) { + this.queryField = queryField; + } + + public List getArgumentField() { + return argumentField; + } + + public void setArgumentField(List argumentField) { + this.argumentField = argumentField; + } + + public GrafanaPostLoookupField( + List postQuery, List argumentField) { + this.queryField = postQuery; + this.argumentField = argumentField; + } + + public GrafanaPostLoookupField(GrafanaPostLoookupField httpPostLoookupField) { + this.queryField = httpPostLoookupField.queryField; + this.argumentField = httpPostLoookupField.argumentField; + } + + public GrafanaPostLoookupField() {} +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostMeta.java b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostMeta.java new file mode 100644 index 00000000000..c01736e6e30 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostMeta.java @@ -0,0 +1,425 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.plc4x.hop.utils.transforms.grafana; + +import org.apache.hop.core.CheckResult; +import org.apache.hop.core.ICheckResult; +import org.apache.hop.core.annotations.Transform; +import org.apache.hop.core.exception.HopTransformException; +import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.row.IValueMeta; +import org.apache.hop.core.row.value.ValueMetaInteger; +import org.apache.hop.core.row.value.ValueMetaString; +import org.apache.hop.core.util.Utils; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.metadata.api.HopMetadataProperty; +import org.apache.hop.metadata.api.IHopMetadataProvider; +import org.apache.hop.pipeline.Pipeline; +import org.apache.hop.pipeline.PipelineMeta; +import org.apache.hop.pipeline.transform.BaseTransformMeta; +import org.apache.hop.pipeline.transform.ITransformMeta; +import org.apache.hop.pipeline.transform.TransformMeta; + +import java.util.ArrayList; +import java.util.List; + +/* +* This code is taken from the "HttpPost" transform to be adapted for use +* with the Grafana APIs. +* In the future, its integration with the original version should be proposed +* to the working group of Apache Hop +*/ + +@Transform( + id = "grafana-post", + image = "grafana.svg", + name = "i18n::BaseTransform.TypeLongDesc.GrafanaPost", + description = "i18n::BaseTransform.TypeTooltipDesc.HTTPPOST", + categoryDescription = "i18n:org.apache.plc4x.hop.transforms.plc4xinput.messages:Plc4x.Category.plc4x", + keywords = "i18n::HttpPostMeta.keyword", + documentationUrl = "/pipeline/transforms/httppost.html") +public class GrafanaPostMeta extends BaseTransformMeta implements ITransformMeta { + private static final Class PKG = GrafanaPostMeta.class; // For Translator + + // the timeout for waiting for data (milliseconds) + public static final int DEFAULT_SOCKET_TIMEOUT = 10000; + + // the timeout until a connection is established (milliseconds) + public static final int DEFAULT_CONNECTION_TIMEOUT = 10000; + + // the time to wait till a connection is closed (milliseconds)? -1 is no not close. + public static final int DEFAULT_CLOSE_CONNECTIONS_TIME = -1; + + public static final String DEFAULT_ENCODING = "UTF-8"; + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.socketTimeout") + private String socketTimeout; + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.connectionTimeout") + private String connectionTimeout; + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.closeIdleConnectionsTime") + private String closeIdleConnectionsTime; + + /** URL / service to be called */ + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.url") + private String url; + + @HopMetadataProperty(key = "lookup", injectionGroupDescription = "HTTPPOST.Injection.lookupfield") + private List lookupfield = new ArrayList<>(); + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.urlInField") + private boolean urlInField; + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.urlField") + private String urlField; + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.requestEntity") + private String requestEntity; + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.encoding") + private String encoding; + + @HopMetadataProperty(key = "postafile", injectionKeyDescription = "HTTPPOST.Injection.postAFile") + private boolean postAFile; + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.proxyHost") + private String proxyHost; + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.proxyPort") + private String proxyPort; + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.httpLogin") + private String httpLogin; + + @HopMetadataProperty(password = true, injectionKeyDescription = "HTTPPOST.Injection.httpPassword") + private String httpPassword; + + @HopMetadataProperty( + key = "result", + injectionGroupDescription = "HTTPPOST.Injection.httpPostResultField") + private List httpPostResultField = new ArrayList<>(); + + public GrafanaPostMeta() { + super(); // allocate BaseTransformMeta + } + + public String getEncoding() { + return encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** @return Returns the connectionTimeout. */ + public String getConnectionTimeout() { + return connectionTimeout; + } + + /** @param connectionTimeout The connectionTimeout to set. */ + public void setConnectionTimeout(String connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + + /** @return Returns the closeIdleConnectionsTime. */ + public String getCloseIdleConnectionsTime() { + return closeIdleConnectionsTime; + } + + /** @param closeIdleConnectionsTime The connectionTimeout to set. */ + public void setCloseIdleConnectionsTime(String closeIdleConnectionsTime) { + this.closeIdleConnectionsTime = closeIdleConnectionsTime; + } + + /** @return Returns the socketTimeout. */ + public String getSocketTimeout() { + return socketTimeout; + } + + /** @param socketTimeout The socketTimeout to set. */ + public void setSocketTimeout(String socketTimeout) { + this.socketTimeout = socketTimeout; + } + + /** @return Returns the procedure. */ + public String getUrl() { + return url; + } + + /** @param procedure The procedure to set. */ + public void setUrl(String procedure) { + this.url = procedure; + } + + /** @return Is the url coded in a field? */ + public boolean isUrlInField() { + return urlInField; + } + + public boolean isPostAFile() { + return postAFile; + } + + public void setPostAFile(boolean postafile) { + this.postAFile = postafile; + } + + /** @param urlInField Is the url coded in a field? */ + public void setUrlInField(boolean urlInField) { + this.urlInField = urlInField; + } + + /** @return The field name that contains the url. */ + public String getUrlField() { + return urlField; + } + + /** @param urlField name of the field that contains the url */ + public void setUrlField(String urlField) { + this.urlField = urlField; + } + + /** @param requestEntity the requestEntity to set */ + public void setRequestEntity(String requestEntity) { + this.requestEntity = requestEntity; + } + + /** @return requestEntity */ + public String getRequestEntity() { + return requestEntity; + } + + public List getLookupfield() { + return lookupfield; + } + + public void setLookupfield(List lookupfield) { + this.lookupfield = lookupfield; + } + + public List getHttpPostResultField() { + return httpPostResultField; + } + + public void setHttpPostResultField(List httpPostResultField) { + this.httpPostResultField = httpPostResultField; + } + + @Override + public Object clone() { + GrafanaPostMeta retval = (GrafanaPostMeta) super.clone(); + + return retval; + } + + @Override + public void setDefault() { + encoding = DEFAULT_ENCODING; + postAFile = false; + lookupfield.add(new GrafanaPostLoookupField()); + httpPostResultField.add(new GrafanaPostResultField()); + socketTimeout = String.valueOf(DEFAULT_SOCKET_TIMEOUT); + connectionTimeout = String.valueOf(DEFAULT_CONNECTION_TIMEOUT); + closeIdleConnectionsTime = String.valueOf(DEFAULT_CLOSE_CONNECTIONS_TIME); + } + + @Override + public void getFields( + IRowMeta inputRowMeta, + String name, + IRowMeta[] info, + TransformMeta nextTransform, + IVariables variables, + IHopMetadataProvider metadataProvider) + throws HopTransformException { + if (!Utils.isEmpty(httpPostResultField.get(0).getName())) { + IValueMeta v = new ValueMetaString(httpPostResultField.get(0).getName()); + inputRowMeta.addValueMeta(v); + } + + if (!Utils.isEmpty(httpPostResultField.get(0).getCode())) { + IValueMeta v = new ValueMetaInteger(httpPostResultField.get(0).getCode()); + inputRowMeta.addValueMeta(v); + } + if (!Utils.isEmpty(httpPostResultField.get(0).getResponseTimeFieldName())) { + IValueMeta v = + new ValueMetaInteger( + variables.resolve(httpPostResultField.get(0).getResponseTimeFieldName())); + inputRowMeta.addValueMeta(v); + } + String headerFieldName = + variables.resolve(httpPostResultField.get(0).getResponseHeaderFieldName()); + if (!Utils.isEmpty(headerFieldName)) { + IValueMeta v = new ValueMetaString(headerFieldName); + v.setOrigin(name); + inputRowMeta.addValueMeta(v); + } + } + + @Override + public void check( + List remarks, + PipelineMeta pipelineMeta, + TransformMeta transformMeta, + IRowMeta prev, + String[] input, + String[] output, + IRowMeta info, + IVariables variables, + IHopMetadataProvider metadataProvider) { + CheckResult cr; + + // See if we have input streams leading to this transform! + if (input.length > 0) { + cr = + new CheckResult( + ICheckResult.TYPE_RESULT_OK, + BaseMessages.getString( + PKG, "HTTPPOSTMeta.CheckResult.ReceivingInfoFromOtherTransforms"), + transformMeta); + remarks.add(cr); + } else { + cr = + new CheckResult( + ICheckResult.TYPE_RESULT_ERROR, + BaseMessages.getString(PKG, "HTTPPOSTMeta.CheckResult.NoInpuReceived"), + transformMeta); + remarks.add(cr); + } + + // check Url + if (urlInField) { + if (Utils.isEmpty(urlField)) { + cr = + new CheckResult( + ICheckResult.TYPE_RESULT_ERROR, + BaseMessages.getString(PKG, "HTTPPOSTMeta.CheckResult.UrlfieldMissing"), + transformMeta); + } else { + cr = + new CheckResult( + ICheckResult.TYPE_RESULT_ERROR, + BaseMessages.getString(PKG, "HTTPPOSTMeta.CheckResult.UrlfieldOk"), + transformMeta); + } + + } else { + if (Utils.isEmpty(url)) { + cr = + new CheckResult( + ICheckResult.TYPE_RESULT_ERROR, + BaseMessages.getString(PKG, "HTTPPOSTMeta.CheckResult.UrlMissing"), + transformMeta); + } else { + cr = + new CheckResult( + ICheckResult.TYPE_RESULT_OK, + BaseMessages.getString(PKG, "HTTPPOSTMeta.CheckResult.UrlOk"), + transformMeta); + } + } + remarks.add(cr); + } + + public GrafanaPost createTransform( + TransformMeta transformMeta, + GrafanaPostData data, + int cnr, + PipelineMeta pipelineMeta, + Pipeline pipeline) { + return new GrafanaPost(transformMeta, this, data, cnr, pipelineMeta, pipeline); + } + + public GrafanaPostData getTransformData() { + return new GrafanaPostData(); + } + + @Override + public boolean supportsErrorHandling() { + return true; + } + + /** + * ISetter + * + * @param proxyHost + */ + public void setProxyHost(String proxyHost) { + this.proxyHost = proxyHost; + } + + /** + * IGetter + * + * @return + */ + public String getProxyHost() { + return proxyHost; + } + + /** + * ISetter + * + * @param proxyPort + */ + public void setProxyPort(String proxyPort) { + this.proxyPort = proxyPort; + } + + /** + * IGetter + * + * @return + */ + public String getProxyPort() { + return this.proxyPort; + } + + /** + * ISetter + * + * @param httpLogin + */ + public void setHttpLogin(String httpLogin) { + this.httpLogin = httpLogin; + } + + /** + * IGetter + * + * @return + */ + public String getHttpLogin() { + return httpLogin; + } + + /** + * ISetter + * + * @param httpPassword + */ + public void setHttpPassword(String httpPassword) { + this.httpPassword = httpPassword; + } + + /** @return */ + public String getHttpPassword() { + return httpPassword; + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostQuery.java b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostQuery.java new file mode 100644 index 00000000000..6e6f259a393 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostQuery.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.utils.transforms.grafana; + +import org.apache.hop.metadata.api.HopMetadataProperty; + +public class GrafanaPostQuery { + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.QueryFieldName") + private String name; + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.QueryFieldParameter") + private String parameter; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getParameter() { + return parameter; + } + + public void setParameter(String parameter) { + this.parameter = parameter; + } + + public GrafanaPostQuery(String name, String parameter) { + this.name = name; + this.parameter = parameter; + } + + public GrafanaPostQuery(GrafanaPostQuery httpPostQuery) { + this.name = httpPostQuery.name; + this.parameter = httpPostQuery.parameter; + } + + public GrafanaPostQuery() {} +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostResultField.java b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostResultField.java new file mode 100644 index 00000000000..afdd547fb95 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/java/org/apache/plc4x/hop/utils/transforms/grafana/GrafanaPostResultField.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.utils.transforms.grafana; + +import org.apache.hop.metadata.api.HopMetadataProperty; + +public class GrafanaPostResultField { + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.ResultFieldCode") + private String code; + + @HopMetadataProperty(injectionKeyDescription = "HTTPPOST.Injection.ResultFieldName") + private String name; + + @HopMetadataProperty( + key = "response_time", + injectionKeyDescription = "HTTPPOST.Injection.ResultFieldResponseTime") + private String responseTimeFieldName; + + @HopMetadataProperty( + key = "response_header", + injectionKeyDescription = "HTTPPOST.Injection.ResultFieldResponseHeader") + private String responseHeaderFieldName; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getResponseTimeFieldName() { + return responseTimeFieldName; + } + + public void setResponseTimeFieldName(String responseTimeFieldName) { + this.responseTimeFieldName = responseTimeFieldName; + } + + public String getResponseHeaderFieldName() { + return responseHeaderFieldName; + } + + public void setResponseHeaderFieldName(String responseHeaderFieldName) { + this.responseHeaderFieldName = responseHeaderFieldName; + } + + public GrafanaPostResultField( + String code, String name, String responseTimeFieldName, String responseHeaderFieldName) { + this.code = code; + this.name = name; + this.responseTimeFieldName = responseTimeFieldName; + this.responseHeaderFieldName = responseHeaderFieldName; + } + + public GrafanaPostResultField(GrafanaPostResultField httpPostResultField) { + this.code = httpPostResultField.code; + this.name = httpPostResultField.name; + this.responseTimeFieldName = httpPostResultField.responseTimeFieldName; + this.responseHeaderFieldName = httpPostResultField.responseHeaderFieldName; + } + + public GrafanaPostResultField() { + this.code = "result"; + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/resources/grafana.svg b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/resources/grafana.svg new file mode 100644 index 00000000000..ff8c2c5fabd --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/resources/grafana.svg @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/resources/org/apache/plc4x/hop/utils/transforms/grafana/messages/messages_en_US.properties b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/resources/org/apache/plc4x/hop/utils/transforms/grafana/messages/messages_en_US.properties new file mode 100644 index 00000000000..3904e5caa47 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-utils/hop-plc4x-grafana/src/main/resources/org/apache/plc4x/hop/utils/transforms/grafana/messages/messages_en_US.properties @@ -0,0 +1,138 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +BaseTransform.TypeTooltipDesc.HTTPPOST=Call a web service request over HTTP by supplying a base URL by allowing parameters to be set dynamically +BaseTransform.TypeLongDesc.GrafanaPost=Grafana post +HTTPPOSTMeta.Exception.UnableToReadTransformMeta=Unable to read transform information from XML +HTTPPOST.Log.StartingToRun=Starting to run ... +HTTPPOSTDialog.UrlInField.Label=Accept URL from field? +HTTPPOSTDialog.QueryParameters.Label=Query parameters +HTTPPOSTDialog.ColumnInfo.Name=Name +HTTPPOSTDialog.InvalidConnection.DialogMessage=Please select a valid connection\! +HTTPPOSTDialog.UrlField.Tooltip=URL field name +HTTPPOST.Exception.CouldnotFindRequestEntityField=Can not find request entity field [{0}]\! +HTTPPOSTMeta.CheckResult.UrlMissing=URL is missing\! +HTTPPOST.Log.ConnectingToURL=Connecting to [{0}] ... +HTTPPOSTDialog.Log.GettingKeyInfo=getting key info... +HTTPPOSTDialog.URL.Label=URL +HTTPPOST.Log.ResponseCode=The response code is {0} +HTTPPOSTDialog.Log.FoundQueryParameters=Found {0} query parameters +HTTPPOSTDialog.TransformName.Label=Transform name +HTTPPOSTDialog.ColumnInfo.Parameter=Parameter +HTTPPOSTDialog.ColumnInfo.Header=Put in Header? +HTTPPOSTMeta.CheckResult.UrlfieldMissing=URL field is missing\! +HTTPPOSTDialog.AutoCommit.Tooltip=Enable auto commit on this database connection.\nWhen the auto commit is off, a commit is done after the last row is processed. +HTTPPOSTDialog.requestEntity.Label=Request entity field +HTTPPOST.ErrorInTransformRunning=Because of an error, this transform can''t continue\: +HTTPPOSTDialog.UrlField.Label=URL field name +HTTPPOSTMeta.CheckResult.ReceivingInfoFromOtherTransforms=Transform is receiving info from other transforms. +HTTPPOST.LineNumber=linenr +HTTPPOST.Log.DBException=An error occurred, processing will be stopped\: +HTTPPOSTDialog.GetFields.Button=\ &Get Fields +HTTPPOST.Log.ResponseStatusCode=Response status code\: {0} +HTTPPOST.Log.UnableCreateUrl=Unable to create URL. +HTTPPOSTDialog.postAFile.Label=Post a file +HTTPPOST.Log.UnableGetResult=Unable to get result from specified URL \: {0} +HTTPPOSTDialog.postAFile.Tooltip=Post a file +HTTPPOST.Exception.ErrorFindingField=Error finding field [{0}] \! +HTTPPOSTDialog.FailedToGetFields.DialogTitle=Error getting fields +HTTPPOSTMeta.CheckResult.AllArgumentsOK=All arguments found in the input stream. +HTTPPOSTDialog.Log.FoundArguments=Found {0} arguments +HTTPPOSTMeta.CheckResult.UrlOk=URL is specified. +HTTPPOST.Log.ResponseBody=The response body is {0} +HTTPPOSTDialog.ColumnInfo.QueryParameter=Value +HTTPPOST.Log.ErrorFindingField=We can not find field [{0}] in the input stream\! +HTTPPOSTMeta.CheckResult.CouldNotReadFields=Couldn''t read fields from the previous transform. +HTTPPOSTDialog.InvalidConnection.DialogTitle=ERROR +HTTPPOSTDialog.ResultType.Label=Result type +HTTPPOSTDialog.Shell.Title=HTTP post +HTTPPOST.Log.ConnectedToDB=Connected to database... +HTTPPOST.Log.HeaderValue=Header parameter [{0}]=''{1}'' +HTTPPOST.Log.BodyValue=Body parameter [{0}]=''{1}'' +HTTPPOST.Log.QueryValue=Query parameter [{0}]=''{1}'' +HTTPPOSTDialog.Encoding.Label=Encoding +HTTPPOST.Log.Encoding=Header content encoding \: {0} +HTTPPOST.Log.Connecting=Connecting to \: [{0}] +HTTPPOSTMeta.CheckResult.NoInpuReceived=No input received from other transforms\! +HTTPPOSTDialog.FailedToGetFields.DialogMessage=We failed to get fields from previous transform\! +HTTPPOSTMeta.CheckResult.ErrorOccurred=An error occurred\: +HTTPPOSTDialog.Parameters.Label=Body (Header) Parameters \: +HTTPPOSTMeta.CheckResult.MissingArguments=Missing arguments, not found in input from previous transforms\: +HTTPPOST.Log.NoField=URL field name is missing\! +HTTPPOSTMeta.CheckResult.UrlfieldOk=URL field is specified. +HTTPPOSTDialog.Result.Label=Result field name +HTTPPOSTDialog.ResponseTime.Label=Response time (milliseconds) field name +HTTPPOSTDialog.ResponseHeader.Label=Response header field name +HTTPPOSTDialog.ResultCode.Label=HTTP status code field name +HTTPPOSTMeta.CheckResult.WrongTypeArguments=\ (found but wrong type\: {0} vs. {1}) +HTTPPOSTDialog.AutoCommit.Label=Enable auto commit +HTTPPOST.Error.CanNotReadURL=Can not result from [{0}] +HTTPPOST.Log.UnexpectedError=Unexpected error +HTTPPOST.Log.ResponseTime=Response time (milliseconds)\: [{0}] for [{1}] +HTTPPOST.Exception.CouldnotFindField=Couldn''t find field ''{0}'' in row\! +HTTPPOSTMeta.CheckResult.InvalidConnection=Please select or create a connection\! +HTTPPOSTDialog.ColumnInfo.QueryName=Name +HTTPPOSTDialog.HttpAuthGroup.Label=HTTP authentication +HTTPPOSTDialog.HttpLogin.Label=HTTP Login +HTTPPOSTDialog.HttpLogin.Tooltip=HTTP login used to authenticate the call +HTTPPOSTDialog.HttpPassword.Label=HTTP Password +HTTPPOSTDialog.HttpPassword.Tooltip=HTTP password used to authenticate the call +HTTPPOSTDialog.ProxyGroup.Label=Proxy to use +HTTPPOSTDialog.ProxyHost.Label=Proxy Host +HTTPPOSTDialog.ProxyHost.Tooltip=Proxy Host +HTTPPOSTDialog.ProxyPort.Label=Proxy Port +HTTPPOSTDialog.ProxyPort.Tooltip=Proxy Port +HTTPPOST.Exception.Authentication=You need to be authenticated to access the resource at {0}. +HTTPPOST.Exception.IllegalStatusCode=Status code is Illegal: {0}. +HTTPPOST.Error.UnknownHostException=Unknown host {0}. +HTTPPOSTDialog.GeneralTab.Title=General +HTTPPOSTDialog.FieldsTab.Title=Fields +HTTPPOSTDialog.SettingsGroup.Label=Settings +HTTPDialog.OutputFieldsGroup.Label=Output fields +HTTPPOSTDialog.ConnectionTimeOut.Label=Connection timeout +HTTPPOSTDialog.ConnectionTimeOut.Tooltip=The timeout until a connection is established (milliseconds) +HTTPPOSTDialog.SocketTimeOut.Label=Socket timeout +HTTPPOSTDialog.SocketTimeOut.Tooltip=The timeout for waiting for data (milliseconds) +HTTPPOSTDialog.CloseIdleConnectionsTime.Label=Connection close wait time +HTTPPOSTDialog.CloseIdleConnectionsTime.Tooltip=Close all connections older than x milliseconds. +HTTPPOST.Injection.socketTimeout=Socket timeout value (miliseconds) +HTTPPOST.Injection.connectionTimeout=Connection timeout value (miliseconds) +HTTPPOST.Injection.closeIdleConnectionsTime=Connection close wait time (miliseconds) +HTTPPOST.Injection.url=Endpoint URL +HTTPPOST.Injection.lookupfield=Query parameters +HTTPPOST.Injection.urlInField=Accept URL from fieldname (Y/N) +HTTPPOST.Injection.urlField=URL Fieldname +HTTPPOST.Injection.requestEntity=Request entity Fieldname +HTTPPOST.Injection.encoding=Encoding +HTTPPOST.Injection.postAFile=Post a file (Y/N) +HTTPPOST.Injection.proxyHost=Proxy Hostname +HTTPPOST.Injection.proxyPort=Proxy Port +HTTPPOST.Injection.httpLogin=HTTP Login +HTTPPOST.Injection.httpPassword=HTTP Password +HTTPPOST.Injection.httpPostResultField=Result fields +HTTPPOST.Injection.LookupQueryField=Http Post Query fields +HTTPPOST.Injection.LookupArgumentField=Http Post Argument fields +HTTPPOST.Injection.ArgumentFieldName=Body (Header) Field name +HTTPPOST.Injection.ArgumentFieldParameter=Body (Header) value +HTTPPOST.Injection.ArgumentFieldHeader=Put in Header (Y/N) +HTTPPOST.Injection.QueryFieldName=Query parameter field name +HTTPPOST.Injection.QueryFieldParameter=Query parameter value +HTTPPOST.Injection.ResultFieldName=Result field name +HTTPPOST.Injection.ResultFieldCode=HTTP status code field name +HTTPPOST.Injection.ResultFieldResponseTime=Response time (milliseconds) +HTTPPOST.Injection.ResultFieldResponseHeader=Response header field name +HttpPostMeta.keyword=http,post + diff --git a/plc4j/integrations/apache-hop/plc4x-hop-utils/pom.xml b/plc4j/integrations/apache-hop/plc4x-hop-utils/pom.xml new file mode 100644 index 00000000000..d7d3d520904 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-utils/pom.xml @@ -0,0 +1,33 @@ + + + + 4.0.0 + + org.apache.plc4x + plc4j-apache-hop + 0.11.0-SNAPSHOT + + hop-plc4x-utils + pom + PLC4J: Integrations: Apache Hop: Utils + + hop-plc4x-grafana + + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/pom.xml b/plc4j/integrations/apache-hop/pom.xml new file mode 100644 index 00000000000..5908498abb5 --- /dev/null +++ b/plc4j/integrations/apache-hop/pom.xml @@ -0,0 +1,251 @@ + + + + 4.0.0 + + org.apache.plc4x + plc4j-integrations + 0.11.0-SNAPSHOT + + + plc4j-apache-hop + pom + PLC4J: Integrations: Apache Hop + + + + + + 2.3.0 + + /home/hans/Documents/test + + 3.114.0 + 3.1.0 + + 2.2.2.Final + + 0.11.0-SNAPSHOT + 1.4.01 + + + + + plc4x-hop-actions + plc4x-hop-metadata + plc4x-hop-transformer + plc4x-hop-assemblies + plc4x-hop-utils + + + + + + swt-unix + + + unix + + + + org.eclipse.swt.gtk.linux.x86_64 + linux + + + + + org.eclipse.platform + ${swt.artifactId} + ${org.eclipse.platform.version} + + + * + * + + + + + + + + swt-mac + + + mac + + + + org.eclipse.swt.cocoa.macosx.x86_64 + mac + + + + + org.eclipse.platform + ${swt.artifactId} + ${org.eclipse.platform.version} + + + * + * + + + + + + + + swt-windows + + + windows + + + + org.eclipse.swt.win32.win32.x86_64 + windows + + + + + org.eclipse.platform + ${swt.artifactId} + ${org.eclipse.platform.version} + + + * + * + + + + + + + + + + + + central + https://repo1.maven.org/maven2/ + Maven Central + + false + + + true + + + + Apache + https://repository.apache.org/snapshots/ + Apache Repository + + true + + + false + + + + + + apache.snapshots + https://repository.apache.org/snapshots/ + + true + + + false + + + + + + + + + org.apache.rat + apache-rat-plugin + 0.13 + + false + true + + + + DISCLAIMER + LICENSE + NOTICE + **/licenses/* + **/target/** + **/*.svg + **/*.json + **/PUT_JDBC_HERE + **/hop.pwd + **/*.iml + + + **/test/**/*.txt + **/test/**/*.xml + **/test/**/*.xsd + **/test/**/*.csv + **/test/**/*.csv.bz2 + **/test/**/*.csv.gz + **/test/**/*.ods + **/test/**/*.xls + **/test/**/*.xlsx + **/test/**/*.edi + **/test/**/*.avro + **/test/**/*.snippet + + + **/datasets/*.csv + **/it/**/*.csv + + + **/integration-tests/**/*.txt + **/integration-tests/**/*.json + **/integration-tests/**/*.json.old + + + + **/src/main/samples/**/*.txt + **/src/main/samples/**/*.csv + + + docs/content/** + docs/resources/** + docs/node_modules/** + docs/.pnp/** + docs/.pnp.js + docs/yarn.lock + + + + + + + + + + + + \ No newline at end of file diff --git a/plc4j/integrations/pom.xml b/plc4j/integrations/pom.xml index 253dcb038b5..28c39abc3d8 100644 --- a/plc4j/integrations/pom.xml +++ b/plc4j/integrations/pom.xml @@ -37,6 +37,7 @@ apache-nifi apache-calcite opcua-server + apache-hop diff --git a/src/site/asciidoc/developers/protocols/ads/images/ads-statemachine.svg b/src/site/asciidoc/developers/protocols/ads/images/ads-statemachine.svg new file mode 100644 index 00000000000..b3923580aec --- /dev/null +++ b/src/site/asciidoc/developers/protocols/ads/images/ads-statemachine.svg @@ -0,0 +1 @@ +ConnectedConnectBrowseReadWriteSubscribeUnsubscribeinitializingSend 'Add Or Update AMS Routes'Send 'ADS Read Device Info'Receive 'Add Or Update AMS Routes'Receive 'ADS Read Device Info'Init Read Online and Offline VersionReset Symbol and Data-Type DataSend 'Read Online-Version (Symbolic)'Send 'Read Offline-Version'Receive 'Read Online-Version (Symbolic)'Receive 'Read Offline-Version'Send 'Read Symbol- and Data-Type-Table sizes'Receive 'Read Symbol- and Data-Type-Table sizes'Send 'Read Data-Type-Table'Receive 'Read Data-Type-Table'Send 'Read Symbol-Table'Receive 'Read Symbol-Table'Subscribe to changes to the Online- and Offline VersionBrowseBrowse: Send 'Read Symbol- and Data-Type-Table sizes'Browse: Receive 'Read Symbol- and Data-Type-Table sizes'Browse: Send 'Read Data-Type-Table'Browse: Receive 'Read Data-Type-Table'Browse: Send 'Read Symbol-Table'Browse: Receive 'Read Symbol-Table'Return API Browse ResultReadRead: Send 'Multi Item Address Resolution' for unresolvedRead: Receive 'Multi Item Address Resolution' for unresolvedRead: Send 'Multi Item Read'Read: Receive 'Multi Item Read'Read: Return API Read ResultRead: Send 'Single Item Address Resolution'Read: Receive 'Single Item Address Resolution'Read: Send 'Single Item Read'Read: Receive 'Single Item Read'WriteWrite: Send 'Multi Item Address Resolution' for unresolvedWrite: Receive 'Multi Item Address Resolution' for unresolvedWrite: Send 'Multi Item Write'Write: Receive 'Multi Item Write'Write: Return API Write ResultWrite: Send 'Single Item Address Resolution'Write: Receive 'Single Item Address Resolution'Write: Send 'Single Item Write'Write: Receive 'Single Item Write'SubscribeSubscribe: Send 'Multi Item Address Resolution' for unresolvedSubscribe: Receive 'Multi Item Address Resolution' for unresolvedSubscribe: Send 'Single Item Address Resolution'Subscribe: Receive 'Single Item Address Resolution'Subscribe: Send 'Single Item 1 Subscibe'Subscribe: Receive 'Single Item 1 Subscibe'Subscribe: Send 'Single Item 2 Subscibe'Subscribe: Receive 'Single Item 2 Subscibe'Subscribe: Send 'Single Item n Subscibe'Subscribe: Receive 'Single Item n Subscibe'Subscribe: Return API Write ResultUnsubscribeUnsubscribe: Send 'Single Item 1 Unsubscribe'Unsubscribe: Receive 'Single Item 1 Unsubscribe'Unsubscribe: Send 'Single Item 2 Unsubscribe'Unsubscribe: Receive 'Single Item 2 Unsubscribe'Unsubscribe: Send 'Single Item n Unsubscribe'Unsubscribe: Receive 'Single Item n Unsubscribe'Unsubscribe: Return API Unsubscribe ResultAPI Browse RequestAPI Read RequestAPI Write RequestAPI Subscription RequestAPI Unsubscription RequestUsing Authentication?truefalseConfig: Monitor PLC changes?truefalseConfig: Load Symbol- and Data-Type-Tables?truefalseConfig: Monitor PLC changes?trueUpdate the online- or offline version (Depending on wich one changed)Is symbol- and data-type-table loaded?truefalseIs single item read request?falseAre all field addresses resolved?unresolvedresolvedtrueIs the field address resolved?falsetrueIs single item write request?falseAre all field addresses resolved?unresolvedresolvedtrueIs the field address resolved?falsetrueIs single item subscription request?falseAre all field addresses resolved?unresolvedresolvedtrueIs the field address resolved?falsetrue \ No newline at end of file diff --git a/src/site/asciidoc/images/plc4x-architecture.png b/src/site/asciidoc/images/plc4x-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..4891a28c492ac99d330f5eb0d3eeae724c71a89a GIT binary patch literal 24761 zcmeEuXIN9&+9)#?Y``cg3IZx9B27U+YE)D}q(~8w5|t)hdJR!fP?6rGi%4(MOCS*o z9U?W<1f>T;ARz=&?+!SQbI$qh{cd}nTTXt2P4-@Ez3W|XFZ+d_jylI4-aTw=Y#f>z zSM}N0w#~7z{jR#}ci@*dJvFjyZ1)~(UcGGSW3kw{*T>A*7q6np#&hLNv)K*N8WEiF z-QyqFp9F4Ky)rNBlsT=Fd_{*(GW*fpJrV&2Z}^SG<|yYv^acDlMV!=HcW)0swD6cD zIGR*Xr#LFW!6!|t9Zkp`8bVzfn8L>EN}~?p*ORNr=_>y7WdFd(j7F42h3p6(nt+a0 zmq`)@AYx<7^OdG-Ua<8GTv*z?5}inDh8)mus+hhx97F7(;L zl~{i-?Rn$M&brX}?a$$loB3Hk9N+P^b{p&B9ozpKlYH*2wM}=|+R54zo6Vhas~6}C z#v01uu;u9N=d9123$gQfydW=cyG=!%nPdiXL1oqKYpu{p;M44Kx(|&;4-XIb^$Fo% zt4n@dDm)jKHpi``v{hDBrKv*dv$E9u$c}P_i-2Bs)~E2{LOoJEwAdr(>v{$v5ZRXI{2==pQj=JuPK?VnK*h|Ta{ ze;lAN0E4c5qt9$t3dUSB#6H1T8TX$s z!?)gHbjD};!z*guX3bQuhakpiljb~%)a%nJBhYH{HjFcY3-Ucv#lHNQqOb2VK2gxW zTO@&9_qze16S2Y-t`rH5Rf_GJPSG)oHD^X8Z)7ri#(atjy)U9<;!I)8UI(UQFzC1a z`^Q;ZW??Xn-^Hgus~XB2g{4zN#R3^&e0X|ILV}D6_G=p1C8JgM2H)A@weSAMpuzRk zIMj7^UBYzBT@20G)R{6QO)NaabRIU4#uY{iM&nB9%g-G#h*eQ$o}wnPZOIrKNEZXu zSlqoo48hYmh#-4s45LbMzCg+&vH_2fRc1!shEJE)v{vkAimBF8)?MgietApW+)?3I~q447aorAg5sh}}JTRdjnHD$4Vnj@WK z|9<|zHYO;L5{2_-I?*`<2XZw#Bty~b(_QxDY;tk*cx)nju!!%1agBXVud=`OMeu9d zFtVt_2Qi+gL+*?}0c@a62~nnvYY$l*6l_#vX3cnwM;Dg!(lstc1HRykv8P+=bd z_p2)I%XlO|CNFV3t)+B_Eqrpp)805;=B6(K#q|#mCBhAG5wE7X((wKdKZy=lg-O5V z+z~CQ>=R=PZCF=~jRDA~uNW5_sz{I4E>4p^DdDm#+&ft?ZmOyGn_&zmP@^|Urpw!A{i@oe)~5<0L6xSQ9Ff|2(KvNjP6ML4-{x#s zNBH?AF(+5da&4-_dgr$p|J&^v_(wVs6cJJ8gVzN0E}WB7pH#dr6BO^0-+9lA;(0l6 zmY(k71T1d2*KYZA)9w*1>wbEV#aWqAr~UhTL^t;hofY(+*&C}awQtOq={4VRZ8*yO zXq=k84nUugjE*H#K;S2L)iPR*;LwSM=0PFj{uA@-?%aJYvc!l|lqQj0kMJS%VMY=7 zn`M(ylJdFN)zT@eHV8~f$f4{0MG2l|#Ro?H$^m!R*AO+6!8qdf`07$)~k)Iz4 z8kZ%YseDtuA5-Av*27C-*eJgZYNCKsyvr<(2_DbyP;26QndnzhPSt{zwF&Ol(SxS) zHh^XXb1CxTEE%?m$7re;7*k!j@%_uvq7VGI#hk!~CUM8neL7J(cSpv`R_3#qCeS5o zaxp0qj&m?IuJZ8Unt2xt8dq2atf=~eB*Rk91?6DKoDu3~D}$&-pF0i`5)AwB{GE9C4MKwCWkbkg@L6}2`;Cy5F#pFe;7`u}0A#nRXRtCVn-7CL~~ z)%T5M#XaJjcYiq6b3!Hw55fC08F(h6RVb1+!4C4Ft+Zr3KGN!gT>tItv#H1Y!t9HW zq!sw&ogMA%?HwE(TwL&YJj#Er?u~29UFq2967#!Wnrkl)i47K;*6e<8siZ=6`#CNR z&Y{b0A2>x~h0OgO92VyLa+Q>nLPJ7U1^gr*j+G^JS_$}0?VlepF13*O=IrR`_~b~` zLJ`+*o!erzc|{$2|EX;Xu#7ZO=$@XQzP{Kl8`95#fy=>yMR&?huE!lbss0bEZCP5P z=G3oW^&}JfenROB>z)7rRWR%6mZ#194w}5=f)Dz;SfKv<$A2T_f0h`0YH`)0 zIfC)oQEC*&$47r~PmGMng{3=My|pc$g1J=liXW@GX=HGm+t&7*(&iI0KM?Qp(8UF@ z(#%(NO)u)Q!aL;7*H5;{`nZDomC1-I;c$P)G2huVlvHqE>l;O4{wMT3_CT?^THN%SXhJAVK-1E($-Xk|LiwXoTQ{yDq?@RL|O>+DCN3bXa(RxQ~o zegZ!HV{V&0&pwK&SgC<_o>Kw@*(P8~99z>)&K3$#&U`TYlZA7Ie;^xqp9^yEp5#w3 z4s1QolAAV9HhG`r8b3DKT7%{C-aEXtQI_UNOfiWjx%r zmRDDjNdmmV?rxp7SK`mhd9g+}e~*d%U6XS})9q{b*S5?}g!AJ%twu&hgk|{o`46N3 zKBw{d-5NT3gcTl&v|UzG+gw(fCYjuxpVX-~nHmI&A!#rLt_yG2Ix0GU1lk zDMRtL6=8)#e2NO#JvYJIp;{UGz^Od615WEQDe)tcA9OtOY87wb+ECzs|L7Tpv#)UA z%IC`)-p0@xg%fUJg^$mt^J+$jwB_H4nbdSUn=s`Qllqb)?U?6|9H}5gwr)N^K$RCf z-b}t}*ZNkh%{P7D$I<6fbtD&8d-bbz^?~5kSaq_%kwyNtS)^6yl0v<_4^g)gcgwwb z&$C#eU?_BH$h}&E90|Wqo)HAseNEzv&!V#XfxeC$RK|sJ%FC~Lks@aOn%x~>l8x1N z!O&0MxI)Z`yY)HH`E%zb3yJ2TUON#F2{FfFEJfN*C;%)MV`)1#l_z%Y+GK?6eHLEg z6F(x9sBy~s5Pp>Bj!@j{{$V(C(SUJ_blhnPA4uvZm5$ZH^YO`xaBpZZ=vx!91-dX1 zk+NV6zeg=7O;r?E7rY2HIw8T58FpIgPbfFR4bh3H|J?xKD{dBF z8TyJUr|@^{>M#}~Jj>}X`4{%Y#@d#vu|S2`cF0wU@s*om{0EdH*Nf_{-3)c|ycYaQ z+Dn-JVQ;XN_=ouhuyS4*XbO5{csg1>R0%@F$6{aW0^8o=lB*ykOY8y8<^yxt=o zhaX0mcNxP*8<+tB%them(N-@!ND$;vJKS);Si?;tB274SYDklHkr|r>$IQD7V|sH9 zIm4Ci@+y9H)vL;0{uG)r{o5RKcLY9Cag-jfp`wvODQP^rJgbUV`ufJE0JS4<-l|YM z#|2~RZEvN~Wvq_r(U-s53Q|!dpy?dtAK`Y$1Z!id0<|W)nO1%(*8SPXy2baYm%C~8 zGa?{}BNP4vJwbbVNgEaq*MEo6UtQZf#QqZOJ}x31uS;FRiZfWtab3e{Lw`1$>DFt^;w;Nh+Gci+favpB|&(h%4j0DweK%O?bEdi`?=rw%TKd&*_x#Yj*BKZ19 zqU=In%UVjT)`+U&Nn0NX@ig?RQf`Xm`cx+d4EkF8-M%HeY;oP{{uz*~q*B8mRjV9( z$K6g?Aw7ODyLV&oHg2zxcw4@ik@mMzU4FTiF5IhFP|pDIh(^J{N2J&TPpy?eNT&WJ`({LTo^JLgd1DUw zATLUUw`sX4&lYtE@{jwURuZmKJvUSsbTE|}>g3;kEKP<>P;qQ*Xmmg+ec>pw7*{`4 ztc`(N8 ztb4 zB>MtNg^+4Md2gB`C+U2LJ~W*>oyTN!VMAt6+Bah+P2iFUuQ#stGqD~PvP4Zq293Pr zqW7B*pyJ-XOoDo-`aa}e^e3iE5X4vbY)7nWGHW`Ry-fxK3BtKO|w(%*VM_CzyOn zZZhua{G%ojTU9_m=$qN4cdF&c`)WQEYR@NvE$U~wiQFq^S9IoT3VSP6x6E`S_${22%V#gJjJ7p1(g*u zlpC_L*EcQ#+E`(lj>;GziLAq9g#qqCB$p1AIp2HGASShdU52uQMpb*I>o-nh~}e^{cOD zr{;*Z7V@59C<`jFLoiKOfQFhGzc}@vak) z_r~`qC)Z6WaqXF|>RM{-ikt;?2M-H|nG)0kovV~bjd(NCc9AC5`I4}WXiex+RGd{mC|>+KSUti6n~PV4UKBBsdS zwAiGkyACCRQcK7T-APrZ@i;AoAHsU};KeAcoGPM{++a0{|BL4%jm28HXva{V4(cpw1bjHsv zyohcB4^_D`exekl!@u@%dCW=7imL5jy*>6#_S?=9Ka($jN$4OVZ#(!@xTPY%oOfnL z|0r`>5(pNb?FyEAn|zQM0tkS!#$roSOMd!|LRTJ{rDXj#0JQZ2L1~YbuZx@(0m%^~ zqC8dlKtc$Qa*{7e3=OYY>Tiwm;&zh1NTAGUC$?O-hIuQ`B6it!bLV{8k&)_4DdkD` zRcf7eG-V{`a6ljV7>{?3US3+lrxVbMGpE8Gs#nc+pT4YhEomHJ`i_b&_u>2VQ^JM- z6A%DBf#;i({c}5klM`dm)U#c5F)g~QeYWq{>yqKt*5t(B@g|01F{$mc9dvngh7fy8 zmBNg6XLKCkk^Qq5Ae;E{d)E1LZ~e%$sds*YA^$?%x0Q7s4HBx6a|#%tD)04`K5mvoW6TRj{}Mku853L4LgPx-*3EnRz`|#OE&Bb^bKc5!=H-DJrVb$QqDWAI6_GSsyUHPHGz1F;c&)*Ri z_WZns3eR=7vyI*H-H~cU)z?CrH{5QR%+oGjzy~YDyc5oi`+0*GIJ(g!M#SHAOSIIp zY5K<(!5eLD@qpaNG}r-VFmOz?*60~089en?%3+@UmJNQAuci$B(!|mPLuVl8)MMhN z;>vqBTpyy@-GwzZbwq#OxBwU{H8OPmjbEk4N${QypBBK<*Q?&QI(Ct`KR*9`?eim( z1Mc^Qb9)!e0C0<*QT23U4BBtZw%nH(3w4W0)xWI>;&k|?8V7_k`sFXuRVe>BWi7!z zRCyI!c(Z=9@4Ul|)I(JFNsIhT?3 z9kw>$f~%8$opI##5zGJv0%-cCQfkO}3N&E)imkIpk=_vKEA`1>&V(H#NIpM(uaLsX zq1&*EL#s(KKI=7S!PX>rU`)xj;707W6xwJ3?%HSqs6VhkO#b$3aX1DeVuQY72uWzi zWGKx*gBp3syE!S~9z|r2hTE&Xg%OnXnv)7B&0nqora}gI|INN@P5dZr(G}iixjdkR zN(qfC|J?e0U<^aI$H(efsd>>o)m5IFvQyCwwjB~AF~m1W^))pYR6qo}4odwz^{(hP zaE5?mPburr)!l*S{l3=dS>9}Zgx?qQBxDv<8qkq00a|n<n{9buI}`99!D@K-XPSvd)sVeVjWjg z^f}*%>oEq{kM=|v;TC{0>fevh_O+d7S zgS6perJD!iDGAnd540&cTZk-4)XO)=RV)mwnUbA3()EZYo*h=*fIt8}K!;9fyjE5h zY7_OmU$t>G#uDHX^E*y~Aycne7DsF!Ci+)n|2QH0{VQ{Kdb0}P!E86t?q8BXm!AyY zgpYZl;TvT~A+0BxwwfeMiv$^}^T-$7h9%pVD{L}j=?O&1mKXPPwi2Tuhd^EwLP_ zkQop^OH?z2wdE{zi{hF2;IVU%Zh&kZ`Z`T_sDGSN;00FQ@BVvR&nboM>z%uW)#U-M zGf##a{}WXfc*hU-VcdgVHS+258ICuPGP`(E1&@hB4I$`nfUaa0S$8H{oFy_$EY4;f zKH$D7J02eD_v+eTAvs-G#26i6x_pmeIu(yw0TGo$>!R!F^wBE28OSc3U9qzd0srfI zXF>Ea^B4pB&qcg#JuEs(%)!V1;{i2*m0jPTQ>de1zkr?5tEo;M;J(UlT%7oV6kkDa zQmAbCYJ>eO#dyg~if=}6a69ra3&?btsXfmCeQ2VVVT}0h*`*su8Dc=THDdGjMI0vR zMn*JvLqBzq#4we%9p!~QbfOt=N4sxezOTXZl#%CsVfDg$8$mWV2C@U<2LxZru6i}P zt$_~i4Xo?z6a)nTZg(mU=f9v6zOTzyFo^q4%vRV7t0zvy@t!Zd?&blgneps-|LI@- zs^_-xB8??-)nOlJcA&1`7-a3i zv_iA;E<1H5ZWa=S{eYE<>?Y|oAe{ASK@6mF5u*?CI@6dh9ErVxHFS=cg;f@woFMV)eYq>vT$nRW5 z%^m>(a#jTSUn}rmBjeJ*I-6eqzXt$0pNls1%vK8ywJFhhRFYQo`Io$S2Se+mw+8Z4IN5u4S zTYq%w*-LH(JKORh8ajuLE1Y(fT>?t)fC4;%)!V8nqb1Dg*E@D+t5&{`uGFv*R)`VQ zj20+*`bZq9lM^vz_*;yDtcDIw&8>i~?fi>ESENmaii!%5XmLYMnOxi38T3?N@a~Yt zU16D+V{MV|G`MbGxtL%pVxZ0%kk7lB|1o+z_4@Nb?W~)EFYgJmX1Z==O-)9KNt7N| zZ7-i@nAP3g_;LIu={YOAb(#B41C}Y#qk}sro1X z9V5M8iyXKC*>&7TgMTx9znP2Y<|RKp5vK?F_iz8k!GDqt?A=G5YOHN8bIw=%_V#iA z6IKz)R_+xbCVS#UFcVI$-DB%d44423Hc3N5K{mTiq*AlyxNE$ZM(s{^j&pGwk ze^z1SDqmRIy}bO1YayC7I)nWW{&$>PEB{DVbHAyn@$Pwht?6oe$v!NR?QQTc(1~(| z`%4D^+h3GR5#{mT$m7F*M8=wJN|B&XTfME^&Mw4Z0Y zBBm2e``HIr)$DAK-&?gEXtXPdy2I;TXREbY7JhH%d=&NXIqJcg8%A{=rmUVS-2~(Q5 zyfy<}l~Xd2#}rPE5=tFAot5!Ygojn;gz1T<-KS&GFQw%BxjMfN z59iB%Kc!pig}cj?(zZ5LvX@p?76z-Xl}_hxHJpNXBuL_~1n@Rz&ovom6v{tLbXCA|QSxfu*txi%ngObwp6m4;o6RNyc+sP>xJLY7|AFGjoy&=? z;S;F4H?I8#QJqqJ5>WfJqC&rP6$5Y29f` zRVz6;r;i$E4B4aAV*lDLAb$QoY@+#946y|8|4?I5|HDbRRa?wHmI!C-d_?S$M?IL7 zTqTohfKOGGtgNilSnbM-xY(8S6Hf~Dz%`k0XEn%p2&KO3_o7mdFTH$Pq2iEoj}E_W zDm?#W+ULXxHT8ymIFVO6`g5qwZ-d7559Y(O)e=-q>a81}q=x|(wxir=Utb>}49GXr zjVj+A+nu1go%8bMLL4MdKJ0?r-uLj{Ls~B4{N<}{y%Gx?t7iXX)9WZ45QpqK7DTE4 zF{U5obod@5TPy*6N6~6NHrsTNZ?5h+;6=<5-CU-Uo{kkW7>xA)ERfzUQTOK6CjJ0s z{bfU9&zd0?e~ABun9a3KMK3H7gYMP+1qf>h=0>J#2G916U&jNuyuBx!+Hm~N55)dC zq(=YY*zArbH`eBVSu+00q^i`eguf69oCOD|_#iLY_wxI(&3`uW#Tw$0{k0akH)#6T z@xUto2Kg@v`M(s)T7NkNC!Bur*5>JR><;(069`zotfD8=dIBQ%j^pnHbRyGLO55L` z8ZM8{vppLd%_?vWsr(zS^~(cBZ-v`znm4wreberrfBF~7ScG-t;h60-tHjkZzKvA@ z+q-*m1`Ur|w!o2&l))NrrZey;wS8~Wgy?9J!pnkdQUr>{F-AsKzGg*lw=8yxfk zOn<<7X-iO+>i=&&-QV9oGIDk}X7(B3onGlxWj)MU%}pRANS>qH7aY8jj@0cQFupvw zRFc%$9L{&jl+f^g%k%heJ4ZW8<=!_ip{i zQ19LmM!BuIH7PK`={w+xj?b;ydGI~F-rm}0?)+D9d8O$s+$e@p51@ht)$T#mqV#z; z?t;>w=5cfGJ%>rfF#x1nP-(x1+a$h-PSJxLy0EmAtoQyO4)p)ctx8^40?MT97jfA3 z@M#f|Py#p4b@jDX^16B$Cf!wx4B&T=MB+Yk@U#dJy(V+4GD!KKkOihTIwh@yqi3KV zI;R4GO3WSjGQ+@g5BhF{i*EjM{LMBixw8!|Bw$7>fG}&8mTK~=Gd#D%7L2XoesR^@E7wpAQ=@-8^*eV(Xzh68OXzg@)I!W zIbFRS`mIktsnIhOs+l1Rx`YLGUTfLf3km!g;`^pWx~)S|Ugpw>1ZcGaJGi&@G*D{{ z)Vz$&_&z|rpirLeeV}9de3S5Abv^hptFjaUaMVhtWfzc9xT;;bw`D&1L>*FU2;Qz- z`E?Uz5<)JEO0nQ??dA5%mM|$*uq6g z%jJ+k5zRXySTPPiOBdAVsVS(6>s)S4=>g{VsZ5|`VIQT@|NW&>bRE28wqTJl{34j4 zDPRveCB$@{ACp=fseL#~0Lq^Nr!4h_ieciWhmVrXKgy<&PQySGcmosJdg}DgU z!Qzg1GK>3UOgz5A7w(Uf5b3QhrP zWvm(ne&(ZRreLFM$M^+~h#idBN9uTrQ0Vir6Bh$Nw8d0`;SBFQ>+T#K5|G{|2;I1g zOkYVIYeUI7>8XRuEXT7Fk>Fz;?Zyg;{EYjyR2X@H9eM1@?j0TV@VnX4GT|^YU+BBe z9Xy!#{=~>qv$@XjcBApFgm;W>f*rr5$-Dr3PL_RI>=ckyzb@KHf!sI1$PSaZ@<%Cg zM_-{U2fXD5jCeD|X$#K`7!%%-sR{cR_8w`-BxxQPd_f5$t?sW|Z)$(Z^jdkful+<- z;USH|JHsk+%5S_tz8K;x3sA&})OukiH%Y>`DmZjz z<5Okl$C7Shj}R<{3JYx%xtmlM__(|7L81vxNQNcWZ5#_0OalLt&D7p$bARuq7QRXt zKMFo`9uQbp%#-HDSY@qmPmesCT(BLX`Acf3t@+qe)2KC6?*7`5gq7X+L=_;V9w*5J zGU^>CHk#gOTMP`8y}MskbkN@W%RmH=Y!RcjM$91;R7V@`cltFqKaLDROL`j0S&_-6 z-YVXsFEcPzE9l(2cXy`yng?D0#P`T-p?M3E;5QyZ4N zzziFrupp_lSVCjJe@~F|{a74xy2_hj-B9K{%%gKGE>I^>Ku}PCRw}|deq?QECLP5AN4C4z?RUeSab2NTT4fu9r7sriq_XX+L)r z!o@}EAjPTQexxUmVt^LX!P%c$&vz2b`CS)9UM06K@e>)1Azsxn!9bUbVSN4Paj(N z51Y;91QzOn?s%Z5pHgB!Sc8eSL z@kBdUKLuU5@j+h5l!3I7eOt}fs7~E1WA8l$)Eq=#W*XWP7LqgKaI=0O5N+IcKq7^} zP{U-HF&wegn+5Q_H`{ZCXvw>X# z$+*yYtBFv%jc4ZL%fjzD11j;oOjh(AA{HC|;>Re{?nF=$jL` zAm{k17pMo_zH(IyhzMfHf(yLQ)GVg~EY8on80$4(jRK1yECL_yos5wO6H6 z9tLDz!e$SY@QE~j8C`QWKe(>dj-9^>>A0}O!1o8EXhzKrV;#yRTD;1pZB2=?C4k=a zcx64HD8=;hff5TCHMxF@w=glrNo?1q z38CF&mCA4Z$UvJkMPVVVUQ|Hldd!h3>SCmnJTjvJ;DT@9!hZQBIKutmtl@-$$I2+N zdf@k4Gb-DIVrR!BpmI*-awpSTgc7^K%V__r`)Q|~wQ+8?UUizz1WM^>^-cS6EsrT2;TZS0h7HFblngCq6;a%G(-%1C)-@1YIALx0 zOb>*Zo?SA0v!`G+(7)Ki;Ts@x9Mpr&CmqA7vk`)Nh#>PkU? zRUWhA2~dNgq&E!o>-)doiBY>vx1C?zYt=Yj>MI44Uje&=Po?FR)_cs<`sQ^y15^q7 z6J5S??!vsA)^oFs^8<=hbh^s>~q*en{rZJh1g|2luJdY#&q9o3%)uNB>{a$?_h;tCAY7qmfmMw%axEm8FBib6LN{PiWgC3>XYUi6 z%Nahh9&h1?p{WHX^MbkQWQ&PaXjhzRfH~3Q3(`7N2JLbOX%m_~Rl1v|^43w;kE!VZ zUpjd`Ezc!s#4fabF#)KB<+D!)UFs+uni=klet45*vL8)hN0QnGV3T}ETA5ul)!*Q# z@}m;t6k3pO31wZ)qOAFJf9qP7#XM8JLe9WMJp8-`_omGw-N)1N!{!OSa37FfFTg5a zmq&6q2nK6Fvke?5LJ!~p>_xEl8Gw`5SS=`M!AwL}_7YG5Yjv5qT1E#-p6L}kM38l+ z495{Gr+0M-YL>cJ2iGfB+3P5~_suR^wqe|+^0YTzwB-#0UhYskS;Q*}ZL)q;83pz8 zm};c*u?jJBR7?}hCE(5jAmT!bytx1$@Cu6uy-fEDxCMJ5tZv#=Xj7qANn+qFx%Ejy zdiv9f&Z<2E`p^)D9yLEB-8Y_LbV3QlN@FP#joH{^3Dzjm6^m2kBg^{0B z6C7vSR=&X=>fN;_!j5%0A?NAcE>oE?QhkLHpY3UXT7uA;cD8D$05waaJh2r(l`Q~b zqhCkK(58m=(So2AxAEKEz%O!0n~1BHTSAtW1|3V1x+&0j?$IoLG+Tfm4CaLE`ZJr(c72|W6#N>IOq7vv zkv#nyH_(&efR}uL4ybN=u5Ajj-8@OZ+vDYc{d_t)>TGKtNh-~e176q(NSBMM$`@lY z7y%i&{7yg%8Ozw=?bdB|0x1!TR43_ImcHK0NF~lKe}MX8>-iYiCm~(q#z2b~RiwFw z>}3ZP;DMF&dq*87>2BXJu4X=*k+{)sTMv2b6zRo%GnI& zMIdrHb&#TtS*t28ysKEx?%vy!v2@I@@*52YE;I;znSCDqK>Ib|k7L_!f{y_eh6iMO zB#&Jz{NEc8h#0J?-Qx?L0(vgTfx=tnaPACIl>N)I&Lg^o{Wbj@T`QGs%Gj#FJEW=lB9k*^TUjO5O?Q!aDQS>~tY z%qnU1hxxg`nH?#Zh$mOHtbx2o_n3I7y1nydb;4?IFqbfru|NUoOeQZ7#4$p^nWWFF zd>?j$Q#UHFS)WIubL-8HbpXAS8|v!hotT$X+2Ia>{ln;ZK0d&Jh@4$xM<2PcL-8)y zsA{4$jQ4g%8)sX^f_!Jd8A?zTrM{S(!~xdE?VH)%v5rk!5NYHxCV-qpCm~T`uUgju zfhg~yud=BsuiKVgdJ@e;PaLo<*%uzpgI-Qd>DuT{2B@cCPv0|E0|v{I-hZ7`=OC4g z3AHPf-^LiNQ14QcwZGC-;0AG7Mt6Wf3Zepn0{a4=-Z(#u&b44-{Hs;n<{PFUTF67b z={cv1R?&P*^kQwGeR2gbhI@xoW=qY1Qvp}K@%G0Ll6`FbA9Vu_CW3%tj)e7xKA^}e zU%W_9I^KkI-&p=;b5!Bnoqz|d7A?Xffll3hH(zzQlVHCy2P_DkZ5oh#mwi`F!H6@L ztL$xNZbeU2M}pKFO=jcBPv(G5RVHKXJQH`-+fT5@1KBwWv1yRs79Y(Y4L#tSz2$v$ zKd>tiY@mW0U*aEfb(?sQ388YSSl(p;>nD5#NXI>abG@O=VSie8z`Z^g+yp^tjc;1~ ze90>S^K^*{>HrSdpT`nU9uUkKh1*Z2YA~w22yU z)D`yMJ9ts;6Vqiq6RA=e_7I@)O1_K6^Ah?Aq~xk6H@E{mYYGvL^&4d<0k7v;R%M$5 zWN8@R?Lw{%%2X#8BgR(eI#vr}d3=OIxwgB&$X)f2DD)#hqs-!9C6+P;>>Icn_Wezt z37V_toNlCG)c6G6jHS3*XB*B5Z`t~D;)mxbO^M^PMh)H3z)tH)N$tVcMQ zi=c)UJfnlrg%VsAKrme|RpT3=)T@EzD|b-E;Gx=e^gyJnpWVh1TKZpMY*Ibqg79!2eC$7DuWrDyLOFv^iCP}A*8F|1+v6cGI%of*~Bp%cQlQ!y<(x~iiO_} zBfSk{h<&8r;P@N_PT{j<2!aLhtcJ1ook_9L6n)H*=hg7QTS4{%sk+zNGtSLbU=!M& zR>(N4$Aku?M&%Ol8Z@Y#<@wHWVwB3wVnHtaqRsAwA&q}z>z~>B65}%3ha<`Y7@70bqaJpkW z4j`_09MgTn&Qn96)!ych7urcOB0{8W`1wDaAOocSomKYTxhJi4&hT%LrP2@=6Vi6A ziZ!7w<}+P3g2?PT;0p}-)8~K67ZewxGgph&Y+k=H?7Y6tiC>`x-yUWVEYXwREq&Op zt#|S(55AOoaSJw*6w3;E(!?q*@p)rXunCaak9HetKy-B^6X5+HaAKeq0lcK`p}f3q%=^ut#i!NmpQ1KX%KnZ7 z@G`uWvWW>+Y(j(#lzMk~zr%VSH09oVdjKmYR(r4mSsb}flECoL#O-t;AWER&{$Igk zq<6=#DM#eF2J#{XQANocs)uHdIW312YfYanr`qA`#(;P$vorzlZd?Uvea*ubZyW9(h}kZZ$J|H8$j_*twN3`RryC<445bhq&=@6-X%Q=7pAf4p z2O{lDnBbA~7^CLYEDrQ?PqrKPFnyKW(Bd*1^(s$oG}6y*H*Fs4D55#^Lp18M`VBWl z<0R0Ug;4Zdm+-F^cfJF0r{5sS>jE*4J>451G`N?B472S_LDlcxQD{%1_xB`-;>{lf z1$(L(=h`p``L7-E=GO1pnZEO>$#_IzXF4O@KVk{u)VI@a6*Sd&{)_Ibn(ZZ93I-se z#*@q4Uj=tH$W(%Ir#Rxlpgy_jM(#Wswd#YCBBrcV6^L3Z0A2JVpo!_Ex(iUM4SILw z6pR16-PBHzs)PV}iK@6MD^}2&T~@Tn&}X$^OU#26htJkPsOWkFp+1g`+gC}w`JDJ_ zMp({)&CHaI$6+akdIA~{jHT;~GWbcx6BiIsb%~K0BX1Z;S4U6E&#DAMeLf2!CizHp zFM?8u{NPf5w2GJonMe1AJMdPy6%N}Q06A`kOhV_izWp%LgiYzR>0YkSFHI#H1;bb|+4;Y-4B-!lm*Z7O24g+aQ zz^5|_x0U@XQ<)cvTor2Fbf1syRd1$Vs>;|)Gon(rK?f}KnIVAT^&VhF(L+*z+A2E( zq~Aoa9rntFe`VmVs08E)Uf$f_gS!_4y2#PyZvb)laKYimmoVV$#BV^xfk1sZFVddn zHEyLD^&(;Oq3N48b1e_&twziKNfeY5vt@A&#PbqT>B1V z98LSqSiPbZ-#y2j%g@Zhf7jK2&+b3|QsTh&6Kth;SxEBL#tO zWuO~a^}NFH(5NTyih(a2g@Q!YNKFVF>1bPWXbZ`ty*wT#Zjbd)9^3*lXFB~Tuwk&| z=YgS36}*)e&YRK&1+iKp`wj1Z^YI#YJ9;cbeEV#JCw?$SJ^%=>W<6^t;w&GtYPhCe zUGc2pRflsH*|p0hbpwn@lq&(=1u7J5-EAhegQK zOH3UZ_&I+;Nu6BnujnisRC9WCqNF+Juhahs6~8!8i*ffT-N#s_poZe>zWI~oTi2p9 z1BVl!)>IX0O`)3oHy_POUfj%#rhWI*phHd&Z7mDpvpcTp3t`uQoGmNfxbW?YS-AEl z(`}}jpWR@1tkWeR?Mw`szi80t*)6u~sl)fxzwcdVd$~>UW9~Bl=NF~lZ|Yrrr1vag zkN(qY&X@Z|ZVCS({``r?!{fa>z3VM^dFO7sk0H($1qg=4B#eF-cW}Rx*y~m81iILa z7*K`VO!9zXR9~tDE>{px{!~};aE}ACaS@gXHT2#n?QX!Pn86O37uC@tjv{Fxasnfz zsp^Q~7jxbL0_d-~E3ZEWw#19}8T7lLTo}XCh;@77sS2n0rWHz~6uN#D-x~O69uwW@ z(-n^>o1FxEkLX5%Qz3BXLvn5y7|L9s$MQ&xkOS~Njq*#-jWsSzWoXAF0?GVHjmK=% zzngo|h4b$Gl7v}pR-?uf=j4_4(=C*_Tqu1$H}4}R+vDa%u{8_w%tZn?plTy#xO!#c zAwCQ88P9Yd6+zG&RzNjrh);!qlV5Z(G{(ZLRAd%?2o9&UdkdiHSR@_6P_WaD8n;!? zV60GKTzK;h?Godcl7nM`EvqspAA5wG0NqC9Ery}IdI5g&89hSGASX8uQ-YyYbU;@I zX0&Wls1s4fIdc!@y)yymC|wbO6$V52T4`&)mlWJS^4LLhak}I|x($G|9v81YRDR=} zo4U6UY2VUQ-iBpkp1s8^ZjRIWxgD7?cLR^IRhZst3jgLf(M4~wBx#jvbgvM9=a-TR zfjln*E3!7n{e-Cd5mLM7OE3Nku*l}P-1it)>-N=yq|u{Gb)xlmDCTE2fdj@JTvIB! znUwxEQ0bG3{52je#NKP0z^$gF{X9+E+Sz|^>i?XRf(3mGq^{vAU|$k|65_%sfZUE! zx^gg%n_otBuN|Kn6_l07fEKIaVc+G6rZgpQRZFFj;c9N@*)bhh+J+5>X%@zMPCg~D zVxIM7MDo8YI~Exck**3EQO!~ICA@1Sx(r8nRpXwHD%A8j+rmvg4bJ_2ne^KnWS{^z zI5-%1S?5~%=xn^Yqq@?l*GF9Hs9lW=rs%%IDr_I!rq4x=^;KOEs9P99ZEMq{KJG<3 zQQwsVMWP*El@(4RW8HOWUjJp*pU+BdbK8IV0z^4b&+1p-w`A?Gum87a@A+?%OZPqm zu7zjbws>x?^~17rZ@1i@nSX7A>95!}s3%^UM~CiT9(ovf1mKT&9^j#X5sV;q*nt9e zh6Ygs;L7R*)`1dk)NTVF(_fG)2|U_=0~3h7=D_~h4Ci`PStNBpt7ko3{an^LB{Ts5 D86b(e literal 0 HcmV?d00001 From fd4bf09485d6d6849adf0b7bf644ef2a2dc88076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Sat, 11 Mar 2023 13:41:46 -0400 Subject: [PATCH 11/14] Integration with Hop V2.X.X in progress. Action and Transform Read, Write and Events are working, Subscription is missing due to S7 driver problems. The resources for modification are added to the portal. --- .gitignore | 1 + .../bacnetip/readwrite/BACnetVendorId.java | 2 - .../hop/actions/ActionSampleMetaData.java | 4 +- .../hop/actions/Plc4xCheckConnections.java | 72 +++- .../hop/actions/Plc4xCheckDisConnections.java | 271 +++++++++++++ .../Plc4xCheckDisConnectionsDialog.java | 371 ++++++++++++++++++ .../messages/messages_en_US.properties | 13 +- .../src/assembly/assembly.xml | 33 +- .../src/assembly/assembly.xml | 49 +++ .../apache-hop/plc4x-hop-metadata/pom.xml | 18 +- .../apache-hop/plc4x-hop-transformer/pom.xml | 16 + .../hop/transforms/plc4xevent/Plc4xEvent.java | 165 +++++--- .../plc4xevent/Plc4xEventDialog.java | 17 +- .../transforms/plc4xevent/Plc4xEventMeta.java | 22 +- .../hop/transforms/plc4xinput/Plc4xRead.java | 28 +- .../plc4xinput/Plc4xReadDialog.java | 2 +- .../transforms/plc4xinput/Plc4xReadMeta.java | 36 +- .../transforms/plc4xoutput/Plc4xWrite.java | 22 +- .../plc4xoutput/Plc4xWriteMeta.java | 36 +- .../hop/transforms/plc4xsubs/Plc4xSubs.java | 88 +++-- .../transforms/plc4xsubs/Plc4xSubsMeta.java | 34 +- .../util/Plc4xPlcSubscriptionTag.java | 160 ++++++++ .../{Plc4xPlcField.java => Plc4xPlcTag.java} | 20 +- .../messages/messages_en_US.properties | 14 +- pom.xml | 2 + src/site/asciidoc/index.adoc | 14 + src/site/asciidoc/users/index.adoc | 14 + .../users/integrations/apache-hop.adoc | 41 ++ src/site/resources/images/icons/s7_alert.png | Bin 0 -> 19948 bytes .../resources/images/icons/s7_caution.png | Bin 0 -> 18944 bytes src/site/resources/images/icons/s7_danger.png | Bin 0 -> 20452 bytes src/site/resources/images/icons/s7_dont.png | Bin 0 -> 20067 bytes src/site/resources/images/icons/s7_ex.png | Bin 0 -> 20057 bytes .../resources/images/icons/s7_important.png | Bin 0 -> 19667 bytes src/site/resources/images/icons/s7_note.png | Bin 0 -> 19486 bytes src/site/resources/images/icons/s7_tip.png | Bin 0 -> 20231 bytes src/site/resources/images/icons/s7_toddy.png | Bin 0 -> 20356 bytes .../resources/images/icons/s7_warning.png | Bin 0 -> 19172 bytes .../images/integrations/apache_hop_logo.png | Bin 0 -> 14041 bytes .../images/integrations/plc4x_hop_banner.jpg | Bin 0 -> 81373 bytes src/site/site.xml | 1 + 41 files changed, 1355 insertions(+), 211 deletions(-) create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckDisConnections.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckDisConnectionsDialog.java create mode 100644 plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcSubscriptionTag.java rename plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/{Plc4xPlcField.java => Plc4xPlcTag.java} (85%) create mode 100644 src/site/asciidoc/users/integrations/apache-hop.adoc create mode 100644 src/site/resources/images/icons/s7_alert.png create mode 100644 src/site/resources/images/icons/s7_caution.png create mode 100644 src/site/resources/images/icons/s7_danger.png create mode 100644 src/site/resources/images/icons/s7_dont.png create mode 100644 src/site/resources/images/icons/s7_ex.png create mode 100644 src/site/resources/images/icons/s7_important.png create mode 100644 src/site/resources/images/icons/s7_note.png create mode 100644 src/site/resources/images/icons/s7_tip.png create mode 100644 src/site/resources/images/icons/s7_toddy.png create mode 100644 src/site/resources/images/icons/s7_warning.png create mode 100644 src/site/resources/images/integrations/apache_hop_logo.png create mode 100644 src/site/resources/images/integrations/plc4x_hop_banner.jpg diff --git a/.gitignore b/.gitignore index 39a55e142e7..d86ce58836f 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ atlassian-ide-plugin.xml *.tar.gz *.rar + # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* diff --git a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java index 8f5d0a26fcd..a5f60c30a41 100644 --- a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java +++ b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java @@ -1615,8 +1615,6 @@ public enum BACnetVendorId { THING_WAREHOUSELLC((int) 1404, (int) 1404, (String) "Thing Warehouse LLC"), INNOFRIENDS_GMBH((int) 1405, (int) 1405, (String) "Innofriends GmbH"), METRONICAKP_SPJ((int) 1406, (int) 1406, (String) "Metronic AKP Sp. J."), -<<<<<<< HEAD - TECHKNAVE((int) 1407, (int) 1407, (String) "Techknave"), ELSNER_ELEKTRONIK((int) 1408, (int) 1408, (String) "Elsner Elektronik"), LEFOO_INDUSTRIAL_HANGZHOU_CO_LTD( diff --git a/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/ActionSampleMetaData.java b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/ActionSampleMetaData.java index ecaaf6efdf7..67145901ab6 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/ActionSampleMetaData.java +++ b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/ActionSampleMetaData.java @@ -25,8 +25,8 @@ * @author cgarcia */ @HopMetadata( - key = "Xplc4xconnection", - name = "PLC4x Connection", + key = "Xplc4xaction", + name = "PLC4x Action", description = "A shared PLC4x connection to a PLC", image = "plc4x_toddy.svg", documentationUrl = "/metadata-types/neo4j/neo4j-connection.html") diff --git a/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckConnections.java b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckConnections.java index 752890f7f23..c2aac428f52 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckConnections.java +++ b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckConnections.java @@ -31,25 +31,32 @@ import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.hop.core.Const; import org.apache.hop.core.exception.HopException; import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.apache.plc4x.java.DefaultPlcDriverManager; +import org.apache.plc4x.java.api.PlcConnection; +import org.apache.plc4x.java.api.exceptions.PlcConnectionException; import org.w3c.dom.Node; @Action( id = "CHECK_PLC4X_CONNECTIONS", - name = "i18n::Plc4xAction.Name", - description = "i18n::Plc4xAction.Description", + name = "i18n::Plc4xActionConnections.Name", + description = "i18n::Plc4xActionConnections.Description", image = "plc4x_toddy.svg", categoryDescription = "i18n:org.apache.hop.workflow:ActionCategory.Category.Conditions", - keywords = "i18n::Plc4xAction.keyword", - documentationUrl = "/workflow/actions/checkdbconnection.html") + keywords = "i18n::Plc4xActionConnections.keyword", + documentationUrl = "/workflow/actions/plc4x.html") public class Plc4xCheckConnections extends ActionBase implements Cloneable, IAction { private static final Class PKG = Plc4xCheckConnections.class; // Needed by Translator private Plc4xConnection[] connections; + private boolean connected = false; + private PlcConnection plcconn = null; protected static final String[] unitTimeDesc = new String[] { @@ -241,17 +248,41 @@ public void loadXml( Node entrynode, IHopMetadataProvider metadataProvider, IVar } /** - * Execute this action and return the result. In this case it means, just set the result boolean in the Result + * Execute this action and return the result. + * In this case it means, just set the result boolean in the Result * class. - * - * @param result The result of the previous execution + * Check all conections metadata from the dialog. + * @param prevResult The result of the previous execution * @return The Result of the execution. */ @Override - public Result execute( Result result, int nr ) { - result.setResult(true); - System.out.println("NR: " + nr); - + public Result execute( Result prevResult, int nr ) { + Result result = prevResult; + result.setNrErrors(0); + connected = true; + for (Plc4xConnection connmeta:connections) { + try { + plcconn = new DefaultPlcDriverManager().getConnection(connmeta.getUrl()); //(01) + if (!plcconn.isConnected()) { + logBasic("Cant connect to: " + connmeta.getUrl()); + connected = false; + plcconn = null; + //break; + } + plcconn.close(); + plcconn = null; + } catch (Exception ex) { + Logger.getLogger(Plc4xCheckConnections.class.getName()).log(Level.SEVERE, null, ex); + connected = false; + plcconn = null; + //break; + } finally { + + } + + } + + result.setResult(connected); return result; } @@ -268,4 +299,23 @@ public Result execute( Result result, int nr ) { public void check( List remarks, WorkflowMeta workflowMeta, IVariables variables, IHopMetadataProvider metadataProvider ) { } + + @Override + public boolean resetErrorsBeforeExecution() { + return false; + } + + @Override + public boolean isEvaluation() { + return true; + } + + @Override + public boolean isUnconditional() { + return false; + } + + + + } diff --git a/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckDisConnections.java b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckDisConnections.java new file mode 100644 index 00000000000..d4f3f5e2538 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckDisConnections.java @@ -0,0 +1,271 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.plc4x.hop.actions; + +import org.apache.hop.core.ICheckResult; +import org.apache.hop.core.Result; +import org.apache.hop.core.annotations.Action; +import org.apache.hop.core.exception.HopXmlException; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.core.xml.XmlHandler; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.metadata.api.IHopMetadataProvider; +import org.apache.hop.workflow.WorkflowMeta; +import org.apache.hop.workflow.action.ActionBase; +import org.apache.hop.workflow.action.IAction; + + +import java.util.List; +import org.apache.hop.core.Const; +import org.apache.hop.core.exception.HopException; +import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.w3c.dom.Node; + + +@Action( + id = "CHECK_PLC4X_DISCONNECTIONS", + name = "i18n::Plc4xActionDisConnections.Name", + description = "i18n::Plc4xActionDisConnections.Description", + image = "plc4x_toddy.svg", + categoryDescription = "i18n:org.apache.hop.workflow:ActionCategory.Category.Conditions", + keywords = "i18n::Plc4xActionDisConnections.keyword", + documentationUrl = "/workflow/actions/checkdbconnection.html") +public class Plc4xCheckDisConnections extends ActionBase implements Cloneable, IAction { + private static final Class PKG = Plc4xCheckDisConnections.class; // Needed by Translator + + + private Plc4xConnection[] connections; + + protected static final String[] unitTimeDesc = + new String[] { + BaseMessages.getString(PKG, "Plc4xCheckConnections.UnitTimeMilliSecond.Label"), + BaseMessages.getString(PKG, "Plc4xCheckConnections.UnitTimeSecond.Label"), + BaseMessages.getString(PKG, "Plc4xCheckConnections.UnitTimeMinute.Label"), + BaseMessages.getString(PKG, "Plc4xCheckConnections.UnitTimeHour.Label"), + }; + protected static final String[] unitTimeCode = + new String[] {"millisecond", "second", "minute", "hour"}; + + public static final int UNIT_TIME_MILLI_SECOND = 0; + public static final int UNIT_TIME_SECOND = 1; + public static final int UNIT_TIME_MINUTE = 2; + public static final int UNIT_TIME_HOUR = 3; + + private String[] waitfors; + private int[] waittimes; + + private long timeStart; + private long now; + + public Plc4xCheckDisConnections( String name) { + super(name, ""); + //connections = null; + waitfors = null; + waittimes = null; + } + + public Plc4xCheckDisConnections() { + this( ""); + } + + public Object clone() { + Plc4xCheckDisConnections c = (Plc4xCheckDisConnections) super.clone(); + return c; + } + + + public Plc4xConnection[] getConnections() { + return connections; + } + + public void setConnections(Plc4xConnection[] connections) { + this.connections = connections; + } + + public String[] getWaitfors() { + return waitfors; + } + + public void setWaitfors(String[] waitfors) { + this.waitfors = waitfors; + } + + public int[] getWaittimes() { + return waittimes; + } + + public void setWaittimes(int[] waittimes) { + this.waittimes = waittimes; + } + + public long getTimeStart() { + return timeStart; + } + + public long getNow() { + return now; + } + + private static String getWaitTimeCode(int i) { + if (i < 0 || i >= unitTimeCode.length) { + return unitTimeCode[0]; + } + return unitTimeCode[i]; + } + + public static String getWaitTimeDesc(int i) { + if (i < 0 || i >= unitTimeDesc.length) { + return unitTimeDesc[0]; + } + return unitTimeDesc[i]; + } + + public static int getWaitTimeByDesc(String tt) { + if (tt == null) { + return 0; + } + + for (int i = 0; i < unitTimeDesc.length; i++) { + if (unitTimeDesc[i].equalsIgnoreCase(tt)) { + return i; + } + } + + // If this fails, try to match using the code. + return getWaitTimeByCode(tt); + } + + private static int getWaitTimeByCode(String tt) { + if (tt == null) { + return 0; + } + + for (int i = 0; i < unitTimeCode.length; i++) { + if (unitTimeCode[i].equalsIgnoreCase(tt)) { + return i; + } + } + return 0; + } + + + + /** + * + * Save values to XML + * + * @return + */ + @Override + public String getXml() { + StringBuilder xml = new StringBuilder(120); + xml.append(super.getXml()); + xml.append(" ").append(Const.CR); + if (connections != null) { + for (int i = 0; i < connections.length; i++) { + xml.append(" ").append(Const.CR); + xml.append(" ") + .append( + XmlHandler.addTagValue( + "name", connections[i] == null ? null : connections[i].getName())); + xml.append(" ").append(XmlHandler.addTagValue("waitfor", waitfors[i])); + xml.append(" ") + .append(XmlHandler.addTagValue("waittime", getWaitTimeCode(waittimes[i]))); + xml.append(" ").append(Const.CR); + } + } + xml.append(" ").append(Const.CR); + + return xml.toString(); + } + + /** + * + * Read the XML and get the values needed for the acton + * + * @param entrynode + * @param metadataProvider + * @throws HopXmlException + */ + @Override + public void loadXml( Node entrynode, IHopMetadataProvider metadataProvider, IVariables variables ) throws HopXmlException { + try { + super.loadXml(entrynode); + Node fields = XmlHandler.getSubNode(entrynode, "connections"); + + // How many hosts? + int nrFields = XmlHandler.countNodes(fields, "connection"); + connections = new Plc4xConnection[nrFields]; + waitfors = new String[nrFields]; + waittimes = new int[nrFields]; + // Read them all... + for (int i = 0; i < nrFields; i++) { + Node fnode = XmlHandler.getSubNodeByNr(fields, "connection", i); + String dbname = XmlHandler.getTagValue(fnode, "name"); + + //connections[i] = Plc4xConnection.loadDatabase(metadataProvider, dbname); + if (dbname != null) { + connections[i] = metadataProvider.getSerializer(Plc4xConnection.class).load(dbname); + waitfors[i] = XmlHandler.getTagValue(fnode, "waitfor"); + waittimes[i] = getWaitTimeByCode(Const.NVL(XmlHandler.getTagValue(fnode, "waittime"), "")); + }; + } + } catch (HopXmlException xe) { + throw new HopXmlException( + BaseMessages.getString( + PKG, + "Plc4xCheckConnections.ERROR_0001_Cannot_Load_Job_Entry_From_Xml_Node", + xe.getMessage())); + } catch (HopException ex) { + throw new HopXmlException( + BaseMessages.getString( + PKG, + "Plc4xCheckConnections.ERROR_0001_Cannot_Load_Job_Entry_From_Xml_Node", + ex.getMessage())); + } + } + + /** + * Execute this action and return the result. In this case it means, just set the result boolean in the Result + * class. + * + * @param result The result of the previous execution + * @return The Result of the execution. + */ + @Override + public Result execute( Result result, int nr ) { + result.setResult(true); + System.out.println("NR: " + nr); + + return result; + } + + /** + * + * Add checks to report warnings + * + * @param remarks + * @param workflowMeta + * @param variables + * @param metadataProvider + */ + @Override + public void check( List remarks, WorkflowMeta workflowMeta, IVariables variables, + IHopMetadataProvider metadataProvider ) { + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckDisConnectionsDialog.java b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckDisConnectionsDialog.java new file mode 100644 index 00000000000..75336387996 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/java/org/apache/plc4x/hop/actions/Plc4xCheckDisConnectionsDialog.java @@ -0,0 +1,371 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.plc4x.hop.actions; + +import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.hop.core.Const; +import org.apache.hop.core.exception.HopException; +import org.apache.hop.core.util.Utils; +import org.apache.hop.core.variables.IVariables; +import org.apache.hop.i18n.BaseMessages; +import org.apache.hop.ui.core.dialog.BaseDialog; +import org.apache.hop.ui.core.gui.WindowProperty; +import org.apache.hop.ui.core.widget.ColumnInfo; +import org.apache.hop.ui.core.widget.TableView; +import org.apache.hop.ui.pipeline.transform.BaseTransformDialog; +import org.apache.hop.ui.workflow.action.ActionDialog; +import org.apache.hop.ui.workflow.dialog.WorkflowDialog; +import org.apache.hop.workflow.WorkflowMeta; +import org.apache.hop.workflow.action.IAction; +import org.apache.hop.workflow.action.IActionDialog; +import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.*; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.widgets.*; + +import org.apache.hop.metadata.api.IHopMetadata; +import org.apache.hop.ui.core.dialog.ErrorDialog; +import org.apache.hop.ui.core.metadata.MetadataManager; +import org.apache.hop.ui.core.widget.MetaSelectionLine; + + +public class Plc4xCheckDisConnectionsDialog extends ActionDialog implements IActionDialog { + private static final Class PKG = Plc4xCheckDisConnectionsDialog.class; // Needed by Translator + + private Shell shell; + + private Text wName; + + private Plc4xCheckDisConnections action; + + private boolean changed; + + private TableView wFields; + + private MetaSelectionLine wConnection; + + public Plc4xCheckDisConnectionsDialog(Shell parent, IAction action, WorkflowMeta workflowMeta, IVariables variables) { + super( parent, workflowMeta, variables ); + this.action = (Plc4xCheckDisConnections) action; + if ( this.action.getName() == null ) { + this.action.setName( BaseMessages.getString( PKG, "Plc4xCheckConnections.Label" ) ); + } + } + + @Override + public IAction open() { + Shell parent = getParent(); + + shell = new Shell(parent, SWT.DIALOG_TRIM | SWT.MIN | SWT.MAX | SWT.RESIZE); + props.setLook(shell); + WorkflowDialog.setShellImage(shell, action); + + ModifyListener lsMod = (ModifyEvent e) -> action.setChanged(); + changed = action.hasChanged(); + + FormLayout formLayout = new FormLayout(); + formLayout.marginWidth = Const.FORM_MARGIN; + formLayout.marginHeight = Const.FORM_MARGIN; + + shell.setLayout(formLayout); + shell.setText(BaseMessages.getString(PKG, "Plc4xCheckonnections.Title")); + + int middle = props.getMiddlePct(); + int margin = Const.MARGIN; + + // Buttons at the bottom + // + Button wOk = new Button(shell, SWT.PUSH); + wOk.setText(BaseMessages.getString(PKG, "System.Button.OK")); + wOk.addListener(SWT.Selection, (Event e) -> ok()); + Button wCancel = new Button(shell, SWT.PUSH); + wCancel.setText(BaseMessages.getString(PKG, "System.Button.Cancel")); + wCancel.addListener(SWT.Selection, (Event e) -> cancel()); + BaseTransformDialog.positionBottomButtons(shell, new Button[] {wOk, wCancel}, margin, null); + + // Filename line + Label wlName = new Label(shell, SWT.RIGHT); + wlName.setText(BaseMessages.getString(PKG, "Plc4xCheckConnections.Name.Label")); + props.setLook(wlName); + FormData fdlName = new FormData(); + fdlName.left = new FormAttachment(0, 0); + fdlName.right = new FormAttachment(middle, -margin); + fdlName.top = new FormAttachment(0, margin); + wlName.setLayoutData(fdlName); + wName = new Text(shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + props.setLook(wName); + wName.addModifyListener(lsMod); + FormData fdName = new FormData(); + fdName.left = new FormAttachment(middle, 0); + fdName.top = new FormAttachment(0, margin); + fdName.right = new FormAttachment(100, 0); + wName.setLayoutData(fdName); + + Label wlFields = new Label(shell, SWT.NONE); + wlFields.setText(BaseMessages.getString(PKG, "Plc4xCheckConnections.Fields.Label")); + props.setLook(wlFields); + FormData fdlFields = new FormData(); + fdlFields.left = new FormAttachment(0, 0); + // fdlFields.right= new FormAttachment(middle, -margin); + fdlFields.top = new FormAttachment(wName, 2 * margin); + wlFields.setLayoutData(fdlFields); + + + wConnection = + new MetaSelectionLine<>( + variables, + metadataProvider, + Plc4xConnection.class, + shell, + SWT.NONE, + BaseMessages.getString(PKG, "Plc4xCheckConnections.Connection.Label"), + BaseMessages.getString(PKG, "Plc4xCheckConnections.Connection.Tooltip")); + props.setLook(wConnection); + FormData fdConnection = new FormData(); + fdConnection.left = new FormAttachment(0, 0); + fdConnection.right = new FormAttachment(100, 0); + //fdConnection.top = new FormAttachment(wTransformName, margin); + wConnection.setLayoutData(fdConnection); + + try { + wConnection.fillItems(); + } catch (Exception e) { + new ErrorDialog(shell, "Error", "Error listing Cassandra connection metadata objects", e); + } + + + // Buttons to the right of the screen... + Button wbGetConnections = new Button(shell, SWT.PUSH | SWT.CENTER); + props.setLook(wbGetConnections); + wbGetConnections.setText( + BaseMessages.getString(PKG, "Plc4xCheckConnections.GetConnections")); + wbGetConnections.setToolTipText( + BaseMessages.getString(PKG, "Plc4xCheckConnections.GetConnections.Tooltip")); + FormData fdbGetConnections = new FormData(); + fdbGetConnections.right = new FormAttachment(100, -margin); + fdbGetConnections.top = new FormAttachment(wlFields, margin); + wbGetConnections.setLayoutData(fdbGetConnections); + + // Buttons to the right of the screen... + Button wbdSourceFileFolder = new Button(shell, SWT.PUSH | SWT.CENTER); + props.setLook(wbdSourceFileFolder); + wbdSourceFileFolder.setText( + BaseMessages.getString(PKG, "Plc4xCheckConnections.DeleteEntry")); + wbdSourceFileFolder.setToolTipText( + BaseMessages.getString(PKG, "Plc4xCheckConnections.DeleteSourceFileButton.Label")); + FormData fdbdSourceFileFolder = new FormData(); + fdbdSourceFileFolder.right = new FormAttachment(100, -margin); + fdbdSourceFileFolder.top = new FormAttachment(wbGetConnections, margin); + wbdSourceFileFolder.setLayoutData(fdbdSourceFileFolder); + + int rows = + action.getConnections() == null + ? 1 + : (action.getConnections().length == 0 ? 0 : action.getConnections().length); + + final int FieldsRows = rows; + + ColumnInfo[] colinf = + new ColumnInfo[] { + new ColumnInfo( + BaseMessages.getString(PKG, "Plc4xCheckConnections.Fields.Argument.Label"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + this.getWorkflowMeta().getDatabaseNames(), + false), + new ColumnInfo( + BaseMessages.getString(PKG, "Plc4xCheckConnections.Fields.WaitFor.Label"), + ColumnInfo.COLUMN_TYPE_TEXT, + false), + new ColumnInfo( + BaseMessages.getString(PKG, "Plc4xCheckConnections.Fields.WaitForTime.Label"), + ColumnInfo.COLUMN_TYPE_CCOMBO, + Plc4xCheckConnections.unitTimeDesc, + false), + }; + + colinf[0].setToolTip(BaseMessages.getString(PKG, "Plc4xCheckConnections.Fields.Column")); + colinf[1].setUsingVariables(true); + colinf[1].setToolTip(BaseMessages.getString(PKG, "Plc4xCheckConnections.WaitFor.ToolTip")); + + wFields = + new TableView( + variables, + shell, + SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI, + colinf, + FieldsRows, + lsMod, + props); + + FormData fdFields = new FormData(); + fdFields.left = new FormAttachment(0, 0); + fdFields.top = new FormAttachment(wlFields, margin); + fdFields.right = new FormAttachment(wbGetConnections, -margin); + fdFields.bottom = new FormAttachment(wOk, -2 * margin); + wFields.setLayoutData(fdFields); + + // Delete files from the list of files... + wbdSourceFileFolder.addListener( + SWT.Selection, + e -> { + int[] idx = wFields.getSelectionIndices(); + wFields.remove(idx); + wFields.removeEmptyRows(); + wFields.setRowNums(); + }); + + // get connections... + wbGetConnections.addListener(SWT.Selection, e -> getConnections()); + + getData(); + + BaseDialog.defaultShellHandling(shell, c -> ok(), c -> cancel()); + + return action; + } + + // public void addDatabases() { + // connections = workflowMeta.getDatabaseNames(); + // } + + public void getConnections() { + /* + this.workflowMeta.getMetadataProvider().getMetadataClasses().forEach( + (c) -> { + System.out.println("Name: " + c.getName()); + }); + IHopMetadataProvider hmdp = this.workflowMeta.getMetadataProvider(); + */ + Class metadataClass = null; + + java.util.List databases = new ArrayList<>(); //this.workflowMeta.getMetadataProvider(). + try { + metadataClass = metadataProvider.getMetadataClassForKey("plc4x-connection"); + MetadataManager manager = new MetadataManager<>(variables, metadataProvider, metadataClass, null); + manager.getNames().forEach((s)->{ + try { + databases.add((Plc4xConnection) manager.loadElement(s)); + } catch (HopException ex) { + Logger.getLogger(Plc4xCheckDisConnectionsDialog.class.getName()).log(Level.SEVERE, null, ex); + } + }); + + } catch (Exception ex) { + Logger.getLogger(Plc4xCheckDisConnectionsDialog.class.getName()).log(Level.SEVERE, null, ex); + } + + + wFields.removeAll(); + + for (Plc4xConnection ci : databases) { + if (ci != null) { + wFields.add(new String[] {ci.getName(), "0", Plc4xCheckDisConnections.unitTimeDesc[0]}); + } + } + wFields.removeEmptyRows(); + wFields.setRowNums(); + wFields.optWidth(true); + } + + public void dispose() { + WindowProperty winprop = new WindowProperty(shell); + props.setScreen(winprop); + shell.dispose(); + } + + /** Copy information from the meta-data input to the dialog fields. */ + public void getData() { + if (action.getName() != null) { + wName.setText(action.getName()); + } + + if (action.getConnections() != null) { + for (int i = 0; i < action.getConnections().length; i++) { + TableItem ti = wFields.table.getItem(i); + if (action.getConnections()[i] != null) { + ti.setText(1, action.getConnections()[i].getName()); + ti.setText(2, "" + Const.toInt(action.getWaitfors()[i], 0)); + ti.setText(3, Plc4xCheckDisConnections.getWaitTimeDesc(action.getWaittimes()[i])); + } + } + wFields.setRowNums(); + wFields.optWidth(true); + } + wName.selectAll(); + wName.setFocus(); + } + + private void cancel() { + action.setChanged(changed); + action = null; + dispose(); + } + + private void ok() { + if (Utils.isEmpty(wName.getText())) { + MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR); + mb.setText(BaseMessages.getString(PKG, "System.TransformActionNameMissing.Title")); + mb.setMessage(BaseMessages.getString(PKG, "System.ActionNameMissing.Msg")); + mb.open(); + return; + } + Class metadataClass = null; + action.setName(wName.getText()); + + int nrItems = wFields.nrNonEmpty(); + System.out.println("Numero de items: " + nrItems); + + Plc4xConnection[] connections = new Plc4xConnection[nrItems]; + String[] waitfors = new String[nrItems]; + int[] waittimes = new int[nrItems]; + + + try { + metadataClass = metadataProvider.getMetadataClassForKey("plc4x-connection"); + } catch (HopException ex) { + Logger.getLogger(Plc4xCheckDisConnectionsDialog.class.getName()).log(Level.SEVERE, null, ex); + } + MetadataManager manager = new MetadataManager<>(variables, metadataProvider, metadataClass, null); + + for (int i = 0; i < nrItems; i++) { + String arg = wFields.getNonEmpty(i).getText(1); + Plc4xConnection conn; + try { + conn = (Plc4xConnection) manager.loadElement(arg); + if (conn != null) { + connections[i] = conn; + waitfors[i] = "" + Const.toInt(wFields.getNonEmpty(i).getText(2), 0); + waittimes[i] = + Plc4xCheckDisConnections.getWaitTimeByDesc(wFields.getNonEmpty(i).getText(3)); + } + } catch (HopException ex) { + Logger.getLogger(Plc4xCheckDisConnectionsDialog.class.getName()).log(Level.SEVERE, null, ex); + } + + } + action.setConnections(connections); + action.setWaitfors(waitfors); + action.setWaittimes(waittimes); + + dispose(); + } +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/resources/org/apache/plc4x/hop/actions/messages/messages_en_US.properties b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/resources/org/apache/plc4x/hop/actions/messages/messages_en_US.properties index f13f6255eb2..ae7eb85d961 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/resources/org/apache/plc4x/hop/actions/messages/messages_en_US.properties +++ b/plc4j/integrations/apache-hop/plc4x-hop-actions/src/main/resources/org/apache/plc4x/hop/actions/messages/messages_en_US.properties @@ -17,6 +17,15 @@ # # # +Plc4xActionConnections.Name=Plc4x Action Connections +Plc4xActionConnections.Description=Check Plc4x connections +Plc4xActionConnections.keyword=Plc4x Connections + +Plc4xActionDisConnections.Name=Plc4x Action Disconnections +Plc4xActionDisConnections.Description=Check Plc4x disconnections +Plc4xActionDisConnections.keyword=Plc4x Disconnections + + Plc4xCheckConnections.Name=Check PLC connections Plc4xCheckConnections.Description=Check if we can connect to one or several databases. Plc4xCheckConnections.ConnectionOK=We can successfully connect to database [{0}] (connection [{1}]) @@ -45,5 +54,5 @@ Plc4xCheckConnections.DeleteEntry=Delete Plc4xCheckConnections.GetConnections=Get connections Plc4xCheckConnections.GetConnections.Tooltip=Get available connections Plc4xCheckConnections.keyword=check,plc,database,connection -Plc4xCheckConnections.Connection.Label -Plc4xCheckConnections.Connection.Tooltip \ No newline at end of file +Plc4xCheckConnections.Connection.Label= +Plc4xCheckConnections.Connection.Tooltip= \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/src/assembly/assembly.xml b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/src/assembly/assembly.xml index c79e5135186..984455a9bcb 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/src/assembly/assembly.xml +++ b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-metadata/src/assembly/assembly.xml @@ -57,11 +57,42 @@ com.github.jinahya:bit-io:jar ch.qos.logback:logback-core + io.netty:netty-buffer io.netty:netty-codec:jar + io.netty:netty-codec-dns:jar + io.netty:netty-codec-haproxy:jar + io.netty:netty-codec-http:jar + io.netty:netty-codec-http2:jar + io.netty:netty-codec-memcache:jar + io.netty:netty-codec-mqtt:jar + io.netty:netty-codec-redis:jar + io.netty:netty-codec-smtp:jar + io.netty:netty-codec-socks:jar + io.netty:netty-codec-stomp:jar + io.netty:netty-codec-xml:jar io.netty:netty-common:jar + io.netty:netty-handler:jar + io.netty:netty-handler-proxy:jar + io.netty:netty-ssl-ocsp:jar io.netty:netty-resolver:jar - io.netty:netty-transport + io.netty:netty-resolver-dns:jar + io.netty:netty-resolver-dns-classes-macos:jar + io.netty:netty-transport:jar + io.netty:netty-transport-classes-kqueue:jar + io.netty:netty-transport-native-unix-common:jar + io.netty:netty-transport-rxtx:jar + io.netty:netty-transport-sctp:jar + io.netty:netty-transport-udt:jar + + io.vavr:vavr:jar + io.vavr:vavr-match:jar + + org.apache.plc4x:plc4j-api:jar + org.apache.plc4x:plc4j-spi:jar + org.apache.plc4x:plc4j-spi:jar + org.apache.plc4x:plc4j-transport-tcp:jar + org.apache.plc4x:plc4j-driver-s7:jar diff --git a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/src/assembly/assembly.xml b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/src/assembly/assembly.xml index 3321a4ce6fe..bff52ed295f 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/src/assembly/assembly.xml +++ b/plc4j/integrations/apache-hop/plc4x-hop-assemblies/plc4x-hop-assemblies-transform/src/assembly/assembly.xml @@ -48,5 +48,54 @@ org.apache.plc4x:plc4x-hop-transform:jar + + + + lib + false + true + runtime + + com.github.jinahya:bit-io:jar + ch.qos.logback:logback-core + + io.netty:netty-buffer + io.netty:netty-codec:jar + io.netty:netty-codec-dns:jar + io.netty:netty-codec-haproxy:jar + io.netty:netty-codec-http:jar + io.netty:netty-codec-http2:jar + io.netty:netty-codec-memcache:jar + io.netty:netty-codec-mqtt:jar + io.netty:netty-codec-redis:jar + io.netty:netty-codec-smtp:jar + io.netty:netty-codec-socks:jar + io.netty:netty-codec-stomp:jar + io.netty:netty-codec-xml:jar + io.netty:netty-common:jar + io.netty:netty-handler:jar + io.netty:netty-handler-proxy:jar + io.netty:netty-ssl-ocsp:jar + io.netty:netty-resolver:jar + io.netty:netty-resolver-dns:jar + io.netty:netty-resolver-dns-classes-macos:jar + io.netty:netty-transport:jar + io.netty:netty-transport-classes-kqueue:jar + io.netty:netty-transport-native-unix-common:jar + io.netty:netty-transport-rxtx:jar + io.netty:netty-transport-sctp:jar + io.netty:netty-transport-udt:jar + + io.vavr:vavr:jar + io.vavr:vavr-match:jar + + org.apache.plc4x:plc4j-api:jar + org.apache.plc4x:plc4j-spi:jar + org.apache.plc4x:plc4j-spi:jar + org.apache.plc4x:plc4j-transport-tcp:jar + org.apache.plc4x:plc4j-driver-s7:jar + + + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-metadata/pom.xml b/plc4j/integrations/apache-hop/plc4x-hop-metadata/pom.xml index 22eccd03ab7..84000a4fbe5 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-metadata/pom.xml +++ b/plc4j/integrations/apache-hop/plc4x-hop-metadata/pom.xml @@ -68,7 +68,23 @@ javax.annotation:javax.annotation-api:jar:1.2 - + + + + org.apache.maven.plugins + maven-jar-plugin + + + + + true + lib/ + + + + + + diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/pom.xml b/plc4j/integrations/apache-hop/plc4x-hop-transformer/pom.xml index e707e0d2069..3bd9600ebe6 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-transformer/pom.xml +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/pom.xml @@ -67,6 +67,7 @@ xml-apis:xml-apis:jar:1.4.01 org.apache.plc4x:plc4j-spi:jar:${project.version} com.fasterxml.jackson.core:jackson-annotations:jar:2.14.2 + com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.14.2 @@ -139,5 +140,20 @@ commons-lang3 3.12.0 + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.14.2 + \ No newline at end of file diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEvent.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEvent.java index e87262ec01e..243aa0120b7 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEvent.java +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEvent.java @@ -17,11 +17,17 @@ package org.apache.plc4x.hop.transforms.plc4xevent; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.hop.core.CheckResult; import org.apache.hop.core.Const; import org.apache.hop.core.ICheckResult; @@ -30,8 +36,11 @@ import org.apache.hop.core.exception.HopPluginException; import org.apache.hop.core.logging.LogLevel; import org.apache.hop.core.row.IRowMeta; +import org.apache.hop.core.row.IValueMeta; import org.apache.hop.core.row.RowDataUtil; import org.apache.hop.core.row.RowMeta; +import org.apache.hop.core.row.value.ValueMetaFactory; +import org.apache.hop.core.util.StringUtil; import org.apache.hop.i18n.BaseMessages; import org.apache.hop.metadata.api.IHopMetadataProvider; import org.apache.hop.pipeline.Pipeline; @@ -40,6 +49,7 @@ import org.apache.hop.pipeline.transform.ITransform; import org.apache.hop.pipeline.transform.TransformMeta; import org.apache.plc4x.hop.metadata.Plc4xConnection; +import org.apache.plc4x.hop.transforms.util.Plc4xGeneratorField; import org.apache.plc4x.hop.transforms.util.Plc4xWrapperConnection; import org.apache.plc4x.java.DefaultPlcDriverManager; import org.apache.plc4x.java.api.PlcConnection; @@ -48,14 +58,20 @@ import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse; import org.apache.plc4x.java.api.model.PlcConsumerRegistration; import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.s7.events.S7AlarmEvent; +import org.apache.plc4x.java.s7.events.S7Event; import org.apache.plc4x.java.s7.events.S7ModeEvent; +import org.apache.plc4x.java.s7.events.S7ModeEvent.Fields; +import org.apache.plc4x.java.s7.events.S7SysEvent; +import org.apache.plc4x.java.s7.events.S7UserEvent; import org.apache.plc4x.java.s7.readwrite.ModeTransitionType; /** - * Transform That contains the basic skeleton needed to create your own plugin + * This transform receives an event from the S7 driver, of type MODE, SYS, + * USR or ALM. Only one type can be processed at a time. * */ -public class Plc4xEvent extends BaseTransform implements ITransform { +public class Plc4xEvent extends BaseTransform { public static String FIELD_MODE_EVENT = "MODE"; public static String FIELD_USER_EVENT = "USR"; @@ -75,6 +91,17 @@ public class Plc4xEvent extends BaseTransform im private PlcSubscriptionRequest subsbuild = null; private PlcSubscriptionResponse subresponse = null; + private List remarks = new ArrayList<>(); // stores the errors... + + /* + * The transfer of events is done from the driver tasks. A delay can be added + * for the execution of this transformer. + */ + private ObjectMapper mapper = new ObjectMapper(); + private ConcurrentLinkedQueue events = new ConcurrentLinkedQueue(); + private boolean stopBundle = false; + private int index = 0; + private static final ReentrantLock lock = new ReentrantLock(); private static final String dummy = "dummy"; @@ -91,12 +118,41 @@ public Plc4xEvent(TransformMeta transformMeta, Plc4xEventMeta meta, Plc4xEventDa * @param remarks Error registers * @param origin transform instance name */ - public static final RowMetaAndData buildRow( - Plc4xEventMeta meta, List remarks, String origin) throws HopPluginException { + public static final RowMetaAndData buildRow(Plc4xEventMeta meta, + List remarks, + String origin) throws HopPluginException { IRowMeta rowMeta = new RowMeta(); Object[] rowData = RowDataUtil.allocateRowData(2); int index = 0; - + + ArrayList fields = new ArrayList(); + + if (meta.isModeEvent()) { + for (S7ModeEvent.Fields field:S7ModeEvent.Fields.values()) { + fields.add(field.name()); + } + } else if (meta.isSysEvent()) { + for (S7SysEvent.Fields field:S7SysEvent.Fields.values()) { + fields.add(field.name()); + } + } else if (meta.isUserEvent()) { + for (S7UserEvent.Fields field:S7UserEvent.Fields.values()) { + fields.add(field.name()); + } + } else if (meta.isAlarmEvent()) { + fields.add("ALARM"); + } + + for (String field : fields) { + IValueMeta valueMeta = + ValueMetaFactory.createValueMeta(field, IValueMeta.TYPE_STRING); // build a + rowData[index] = StringUtil.EMPTY_STRING; + // Now add value to the row! + // This is in fact a copy from the fields row, but now with data. + rowMeta.addValueMeta(valueMeta); + index++; + } + return new RowMetaAndData(rowMeta, rowData); } @@ -174,15 +230,7 @@ public boolean processRow() throws HopException { subresponse .getSubscriptionHandle(FIELD_MODE_EVENT) .register(msg -> { - System.out.println("******** S7ModeEvent ********"); - Map map = ((S7ModeEvent) msg).getMap(); - map.forEach((x, y) -> { - System.out.println(x + " : " + y); - }); - short currentmode = (short) - map.get(S7ModeEvent.Fields.CURRENT_MODE.name()); - System.out.println("CURRENT_MODE MSG: " + ModeTransitionType.enumForValue(currentmode).name()); - System.out.println("****************************"); + events.add((S7Event) msg); }); } @@ -191,15 +239,7 @@ public boolean processRow() throws HopException { subresponse .getSubscriptionHandle(FIELD_USER_EVENT) .register(msg -> { - System.out.println("******** S7ModeEvent ********"); - Map map = ((S7ModeEvent) msg).getMap(); - map.forEach((x, y) -> { - System.out.println(x + " : " + y); - }); - short currentmode = (short) - map.get(S7ModeEvent.Fields.CURRENT_MODE.name()); - System.out.println("CURRENT_MODE MSG: " + ModeTransitionType.enumForValue(currentmode).name()); - System.out.println("****************************"); + events.add((S7Event) msg); }); } @@ -208,15 +248,7 @@ public boolean processRow() throws HopException { subresponse .getSubscriptionHandle(FIELD_SYS_EVENT) .register(msg -> { - System.out.println("******** S7ModeEvent ********"); - Map map = ((S7ModeEvent) msg).getMap(); - map.forEach((x, y) -> { - System.out.println(x + " : " + y); - }); - short currentmode = (short) - map.get(S7ModeEvent.Fields.CURRENT_MODE.name()); - System.out.println("CURRENT_MODE MSG: " + ModeTransitionType.enumForValue(currentmode).name()); - System.out.println("****************************"); + events.add((S7Event) msg); }); } @@ -225,15 +257,7 @@ public boolean processRow() throws HopException { subresponse .getSubscriptionHandle(FIELD_ALARM_EVENT) .register(msg -> { - System.out.println("******** S7ModeEvent ********"); - Map map = ((S7ModeEvent) msg).getMap(); - map.forEach((x, y) -> { - System.out.println(x + " : " + y); - }); - short currentmode = (short) - map.get(S7ModeEvent.Fields.CURRENT_MODE.name()); - System.out.println("CURRENT_MODE MSG: " + ModeTransitionType.enumForValue(currentmode).name()); - System.out.println("****************************"); + events.add((S7Event) msg); }); } @@ -256,13 +280,39 @@ public boolean processRow() throws HopException { return false; } + while (events.size() == 0) { + try { + Thread.sleep(100); + if (stopBundle) { + setOutputDone(); // signal end to receiver(s) + return false; + } + } catch (InterruptedException ex) { + break; + } + } + + S7Event s7event = events.poll(); + index = 0; + r = data.outputRowMeta.cloneRow(data.outputRowData); + for (String name:data.outputRowMeta.getFieldNames()) { + System.out.println(name + ": " + s7event.getMap().get(name)); + if (null != s7event.getMap().get(name)) { + r[index++] = s7event.getMap().get(name).toString(); + } else { + try { + r[index++] = mapper.writer() + .writeValueAsString(s7event.getMap()); + } catch (Exception ex) { + Logger.getLogger(Plc4xEvent.class.getName()).log(Level.SEVERE, null, ex); + } + } + } - r = data.outputRowMeta.cloneRow(data.outputRowData); - logBasic("Tamano de los datos: " + r.length); + data.prevDate = data.rowDate; data.rowDate = new Date(); - putRow(data.outputRowMeta, r ); // return your data data.rowsWritten++; return true; @@ -293,7 +343,9 @@ public boolean init() { } data.outputRowData = outputRow.getData(); - data.outputRowMeta = outputRow.getRowMeta(); + data.outputRowMeta = outputRow.getRowMeta(); + + mapper.findAndRegisterModules(); return true; } @@ -313,8 +365,13 @@ public boolean init() { public void cleanup() { super.cleanup(); logBasic("Cleanup. Release connection."); - if (connwrapper != null) - connwrapper.release(); + if (null != connwrapper) { + if (null != registerMode ) registerMode.unregister(); + if (null != registerUser) registerUser.unregister(); + if (null != registerSys) registerSys.unregister(); + if (null != registerAlarm) registerAlarm.unregister(); + connwrapper.release(); + } } @@ -334,11 +391,21 @@ public void dispose() { if (!connwrapper.getConnection().isConnected()){ getPipeline().getExtensionDataMap().remove(meta.getConnection()); } - connwrapper = null; - readRequest = null; + connwrapper = null; + readRequest = null; + registerMode = null; + registerUser = null; + registerSys = null; + registerAlarm = null; } } + + @Override + public void stopRunning() throws HopException { + super.stopRunning(); + stopBundle = true; + } diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventDialog.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventDialog.java index ea369b5cb74..3d246028774 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventDialog.java +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventDialog.java @@ -204,7 +204,7 @@ public void widgetSelected(SelectionEvent e) { * Mode Events ********************/ Label wlModeEvent = new Label(shell, SWT.RIGHT); - wlModeEvent.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.NeverEnding.Label")); + wlModeEvent.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.ModeEvent.Label")); props.setLook(wlModeEvent); FormData fdlModeEvent = new FormData(); fdlModeEvent.left = new FormAttachment(0, 0); @@ -233,7 +233,7 @@ public void widgetSelected(SelectionEvent e) { * User Events ********************/ Label wlUserEvent = new Label(shell, SWT.RIGHT); - wlUserEvent.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.NeverEnding.Label")); + wlUserEvent.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.UserEvent.Label")); props.setLook(wlUserEvent); FormData fdlUserEvent = new FormData(); fdlUserEvent.left = new FormAttachment(0, 0); @@ -262,7 +262,7 @@ public void widgetSelected(SelectionEvent e) { * Sys Events ********************/ Label wlSysEvent = new Label(shell, SWT.RIGHT); - wlSysEvent.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.NeverEnding.Label")); + wlSysEvent.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.SysEvent.Label")); props.setLook(wlSysEvent); FormData fdlSysEvent = new FormData(); fdlSysEvent.left = new FormAttachment(0, 0); @@ -291,7 +291,7 @@ public void widgetSelected(SelectionEvent e) { * Alarm Events ********************/ Label wlAlarmEvent = new Label(shell, SWT.RIGHT); - wlAlarmEvent.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.NeverEnding.Label")); + wlAlarmEvent.setText(BaseMessages.getString(PKG, "Plc4x.Read.Meta.Dialog.AlarmEvent.Label")); props.setLook(wlAlarmEvent); FormData fdlAlarmEvent = new FormData(); fdlAlarmEvent.left = new FormAttachment(0, 0); @@ -544,6 +544,10 @@ public void getData() { wLimit.setText(input.getRowLimit()); wNeverEnding.setSelection(input.isNeverEnding()); + wModeEvent.setSelection(input.isModeEvent()); + wUserEvent.setSelection(input.isUserEvent()); + wSysEvent.setSelection(input.isSysEvent()); + wAlarmEvent.setSelection(input.isAlarmEvent()); setActive(); @@ -560,6 +564,11 @@ private void getInfo( Plc4xEventMeta meta) throws HopException { meta.setConnection(wConnection.getText()); meta.setRowLimit(wLimit.getText()); meta.setNeverEnding(wNeverEnding.getSelection()); + + meta.setModeEvent(wModeEvent.getSelection()); + meta.setUserEvent(wUserEvent.getSelection()); + meta.setSysEvent(wSysEvent.getSelection()); + meta.setAlarmEvent(wAlarmEvent.getSelection()); } diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventMeta.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventMeta.java index 207adb78245..10de092241d 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventMeta.java +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xevent/Plc4xEventMeta.java @@ -49,7 +49,7 @@ categoryDescription = "i18n:org.apache.plc4x.hop.transforms.plc4xevent:Plc4x.Category.plc4x", documentationUrl = "https://plc4x.apache.org/users/integrations/apache-hop.html" ) -public class Plc4xEventMeta extends BaseTransformMeta implements ITransformMeta { +public class Plc4xEventMeta extends BaseTransformMeta { private static final Class PKG = Plc4xEventMeta.class; // Needed by Translator @@ -70,23 +70,23 @@ public class Plc4xEventMeta extends BaseTransformMeta implements ITransformMeta private boolean neverEnding; @HopMetadataProperty( - key = "never_ending", - injectionKeyDescription = "Plc4x.Read.Meta.Injection.NeverEnding") + key = "mode_event", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.ModeEvent") private boolean modeEvent; @HopMetadataProperty( - key = "never_ending", - injectionKeyDescription = "Plc4x.Read.Meta.Injection.NeverEnding") + key = "user_event", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.UserEvent") private boolean userEvent; @HopMetadataProperty( - key = "never_ending", - injectionKeyDescription = "Plc4x.Read.Meta.Injection.NeverEnding") + key = "sys_event", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.SysEvent") private boolean sysEvent; @HopMetadataProperty( - key = "never_ending", - injectionKeyDescription = "Plc4x.Read.Meta.Injection.NeverEnding") + key = "alarm_event", + injectionKeyDescription = "Plc4x.Read.Meta.Injection.AlarmEvent") private boolean alarmEvent; @@ -205,7 +205,7 @@ public void setNeverEnding(boolean neverEnding) { } public boolean isModeEvent() { - return neverEnding; + return modeEvent; } public void setModeEvent(boolean modeEvent) { @@ -213,7 +213,7 @@ public void setModeEvent(boolean modeEvent) { } public boolean isUserEvent() { - return neverEnding; + return userEvent; } public void setUserEvent(boolean userEvent) { diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xRead.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xRead.java index 7b1832c16d1..5e9302da020 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xRead.java +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xRead.java @@ -50,7 +50,7 @@ import org.apache.hop.pipeline.transform.TransformMeta; import org.apache.plc4x.hop.metadata.Plc4xConnection; import org.apache.plc4x.hop.transforms.util.Plc4xGeneratorField; -import org.apache.plc4x.hop.transforms.util.Plc4xPlcField; +import org.apache.plc4x.hop.transforms.util.Plc4xPlcTag; import org.apache.plc4x.hop.transforms.util.Plc4xWrapperConnection; import org.apache.plc4x.java.DefaultPlcDriverManager; import org.apache.plc4x.java.api.PlcConnection; @@ -61,7 +61,7 @@ * Transform That contains the basic skeleton needed to create your own plugin * */ -public class Plc4xRead extends BaseTransform implements ITransform { +public class Plc4xRead extends BaseTransform { private static final Class PKG = Plc4xRead.class; // Needed by Translator @@ -75,7 +75,7 @@ public class Plc4xRead extends BaseTransform imple private static final String dummy = "dummy"; private Map index = new HashMap(); - private Map plcfields = new HashMap(); + private Map plcfields = new HashMap(); public Plc4xRead(TransformMeta transformMeta, Plc4xReadMeta meta, Plc4xReadData data, int copyNr, PipelineMeta pipelineMeta, Pipeline pipeline ) { @@ -89,8 +89,10 @@ public Plc4xRead(TransformMeta transformMeta, Plc4xReadMeta meta, Plc4xReadData * @param remarks Error registers * @param origin transform instance name */ - public static final RowMetaAndData buildRow( - Plc4xReadMeta meta, List remarks, String origin) throws HopPluginException { + public static final RowMetaAndData buildRow(Plc4xReadMeta meta, + List remarks, + String origin) throws HopPluginException { + IRowMeta rowMeta = new RowMeta(); Object[] rowData = RowDataUtil.allocateRowData(meta.getFields().size() + 2); int index = 0; @@ -108,7 +110,7 @@ public static final RowMetaAndData buildRow( for (Plc4xGeneratorField field : meta.getFields()) { int typeString = ValueMetaFactory.getIdForValueMeta(field.getType()); if (StringUtils.isNotEmpty(field.getType())) { - System.out.println("typeString: " + typeString); + IValueMeta valueMeta = ValueMetaFactory.createValueMeta(field.getName(), typeString); // build a // value! @@ -146,7 +148,7 @@ public static final RowMetaAndData buildRow( // try { System.out.println("stringValue: " + stringValue); - rowData[index] = valueMeta.convertData(stringMeta, stringValue); + rowData[index] = valueMeta.convertData(stringMeta, stringValue); } catch (HopValueException e) { switch (valueMeta.getType()) { case IValueMeta.TYPE_NUMBER: @@ -226,7 +228,6 @@ public static final RowMetaAndData buildRow( index++; } } - return new RowMetaAndData(rowMeta, rowData); } @@ -238,17 +239,18 @@ public static final RowMetaAndData buildRow( * 4. Register the connection wrapper for global access. * 5. If the connection to the PLC is made, then it creates the query * and executes it. - * + * TODO: Field validation. */ @Override public boolean processRow() throws HopException { + Object[] r = getRow(); // Get row from input rowset & set row busy! setLogLevel(LogLevel.DEBUG); if ((!meta.isNeverEnding() && data.rowsWritten >= data.rowLimit) && !isStopped()) { setOutputDone(); // signal end to receiver(s) return false; - } + } if (first) { index.clear(); @@ -256,7 +258,7 @@ public boolean processRow() throws HopException { //This performs a minimal check on the user item. //It guarantees that the rates are within those managed by Plc4x. meta.getFields().forEach((f) ->{ - plcfields.put(f.getName(),Plc4xPlcField.of(f.getItem())); + plcfields.put(f.getName(),Plc4xPlcTag.of(f.getItem())); }); first = false; } @@ -282,10 +284,12 @@ public boolean processRow() throws HopException { readRequest = null; try{ PlcConnection conn = new DefaultPlcDriverManager().getConnection(connmeta.getUrl()); //(03) + if (conn.isConnected()) { connwrapper = new Plc4xWrapperConnection(conn); getPipeline().getExtensionDataMap().put(meta.getConnection(), connwrapper); //(04) } + } catch (Exception ex){ setErrors(1L); logError("Unable to create connection to PLC. " + ex.getMessage()); @@ -342,7 +346,7 @@ public boolean processRow() throws HopException { } r = data.outputRowMeta.cloneRow(data.outputRowData); - logBasic("Tamano de los datos: " + r.length); + data.prevDate = data.rowDate; data.rowDate = new Date(); int index = 0; diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadDialog.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadDialog.java index a736e418da0..96a47e5f166 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadDialog.java +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadDialog.java @@ -148,7 +148,7 @@ public String open() { try { wConnection.fillItems(); } catch (Exception e) { - new ErrorDialog(shell, "Error", "Error listing Cassandra connection metadata objects", e); + new ErrorDialog(shell, "Error", "Error listing Plc4x connection metadata objects", e); } Control lastControl = wConnection; diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadMeta.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadMeta.java index 3946c9a310b..c43178958ac 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadMeta.java +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xinput/Plc4xReadMeta.java @@ -50,7 +50,7 @@ categoryDescription = "i18n:org.apache.plc4x.hop.transforms.plc4xinput:Plc4x.Category.plc4x", documentationUrl = "https://plc4x.apache.org/users/integrations/apache-calcite.html" ) -public class Plc4xReadMeta extends BaseTransformMeta implements ITransformMeta { +public class Plc4xReadMeta extends BaseTransformMeta { private static final Class PKG = Plc4xReadMeta.class; // Needed by Translator @@ -121,39 +121,33 @@ public Plc4xReadMeta(Plc4xReadMeta m) { } } - @Override public Plc4xReadMeta clone() { return new Plc4xReadMeta(this); } - @Override public void getFields( IRowMeta inputRowMeta, String name, IRowMeta[] info, TransformMeta nextTransform, IVariables variables, IHopMetadataProvider metadataProvider ) throws HopTransformException { try { - logBasic("PASO 1"); List remarks = new ArrayList<>(); RowMetaAndData rowMetaAndData = Plc4xRead.buildRow(this, remarks, name); - logBasic("PASO 2"); - if (!remarks.isEmpty()) { - logBasic("PASO 3"); - StringBuilder stringRemarks = new StringBuilder(); - for (ICheckResult remark : remarks) { - logBasic("PASO 3x: " + remark.toString()); - stringRemarks.append(remark.toString()).append(Const.CR); + + if (!remarks.isEmpty()) { + StringBuilder stringRemarks = new StringBuilder(); + for (ICheckResult remark : remarks) { + stringRemarks.append(remark.toString()).append(Const.CR); + } + throw new HopTransformException(stringRemarks.toString()); } - logBasic("PASO 3.1"); - throw new HopTransformException(stringRemarks.toString()); - } - logBasic("PASO 4"); - for (IValueMeta valueMeta : rowMetaAndData.getRowMeta().getValueMetaList()) { - valueMeta.setOrigin(name); - } - logBasic("PASO 5"); - inputRowMeta.mergeRowMeta(rowMetaAndData.getRowMeta()); + + for (IValueMeta valueMeta : rowMetaAndData.getRowMeta().getValueMetaList()) { + valueMeta.setOrigin(name); + } + + inputRowMeta.mergeRowMeta(rowMetaAndData.getRowMeta()); } catch (Exception e) { - throw new HopTransformException(e); + throw new HopTransformException(e); } } diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWrite.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWrite.java index 2381564a755..508831b0a5a 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWrite.java +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWrite.java @@ -49,7 +49,7 @@ import org.apache.hop.pipeline.transform.TransformMeta; import org.apache.plc4x.hop.metadata.Plc4xConnection; import org.apache.plc4x.hop.transforms.util.Plc4xGeneratorField; -import org.apache.plc4x.hop.transforms.util.Plc4xPlcField; +import org.apache.plc4x.hop.transforms.util.Plc4xPlcTag; import org.apache.plc4x.hop.transforms.util.Plc4xWrapperConnection; import org.apache.plc4x.java.DefaultPlcDriverManager; import org.apache.plc4x.java.api.PlcConnection; @@ -60,7 +60,7 @@ * Transform That contains the basic skeleton needed to create your own plugin * */ -public class Plc4xWrite extends BaseTransform implements ITransform { +public class Plc4xWrite extends BaseTransform { private static final Class PKG = Plc4xWrite.class; // Needed by Translator @@ -75,7 +75,7 @@ public class Plc4xWrite extends BaseTransform im private static final String dummy = "dummy"; private Map index = new HashMap(); - private Map plcfields = new HashMap(); + private Map plcfields = new HashMap(); public Plc4xWrite(TransformMeta transformMeta, Plc4xWriteMeta meta, Plc4xWriteData data, int copyNr, PipelineMeta pipelineMeta, Pipeline pipeline ) { @@ -108,7 +108,6 @@ public static final RowMetaAndData buildRow( for (Plc4xGeneratorField field : meta.getFields()) { int typeString = ValueMetaFactory.getIdForValueMeta(field.getType()); if (StringUtils.isNotEmpty(field.getType())) { - System.out.println("typeString: " + typeString); IValueMeta valueMeta = ValueMetaFactory.createValueMeta(field.getName(), typeString); // build a // value! @@ -145,7 +144,6 @@ public static final RowMetaAndData buildRow( // Convert the data from String to the specified type ... // try { - System.out.println("stringValue: " + stringValue); rowData[index] = valueMeta.convertData(stringMeta, stringValue); } catch (HopValueException e) { switch (valueMeta.getType()) { @@ -261,7 +259,7 @@ public boolean processRow() throws HopException { Integer i = getInputRowMeta().indexOfValue(f.getName()); //(01) if (i>=0) { index.put(f.getName(), i); - plcfields.put(f.getName(),Plc4xPlcField.of(f.getItem())); + plcfields.put(f.getName(),Plc4xPlcTag.of(f.getItem())); } }); first = false; @@ -309,14 +307,15 @@ public boolean processRow() throws HopException { } finally { lock.unlock(); } - + if ((connmeta != null) && (connwrapper != null)){ if (connwrapper.getConnection().isConnected()){ - + builder = null; builder = connwrapper.getConnection().writeRequestBuilder(); //(05) Integer i; for (Plc4xGeneratorField field: meta.getFields()){ + i = index.get(field.getName()); if (i != null) { //From Input Type @@ -329,7 +328,7 @@ public boolean processRow() throws HopException { case IValueMeta.TYPE_BIGNUMBER: builder.addTagAddress(field.getName(), field.getItem(), - r[i]); + r[i]); break; case IValueMeta.TYPE_DATE: builder.addTagAddress(field.getName(), @@ -369,13 +368,14 @@ public boolean processRow() throws HopException { maxwait = (maxwait<100)?100:maxwait; writeResponse = writeRequest.execute().get(maxwait, TimeUnit.MILLISECONDS); + if (isDebug()) index.forEach((n,y)->{ - System.out.println("Resultado: " + writeResponse.getResponseCode(n)); + logDebug("Result: " + writeResponse.getResponseCode(n)); }); } catch (Exception ex) { setErrors(1L); - logError("Unable read from PLC. " + ex.getMessage()); + logError("Unable write to PLC. " + ex.getMessage()); } } else { diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteMeta.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteMeta.java index d3996ad4a93..d9461f6d07c 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteMeta.java +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xoutput/Plc4xWriteMeta.java @@ -54,7 +54,7 @@ categoryDescription = "i18n:org.apache.plc4x.hop.transforms.plc4xoutput:Plc4x.Category.plc4x", documentationUrl = "https://plc4x.apache.org/users/integrations/apache-calcite.html" ) -public class Plc4xWriteMeta extends BaseTransformMeta implements ITransformMeta { +public class Plc4xWriteMeta extends BaseTransformMeta { private static final Class PKG = Plc4xWriteMeta.class; // Needed by Translator @@ -130,34 +130,28 @@ public Plc4xWriteMeta clone() { return new Plc4xWriteMeta(this); } - - + @Override public void getFields( IRowMeta inputRowMeta, String name, IRowMeta[] info, TransformMeta nextTransform, IVariables variables, IHopMetadataProvider metadataProvider ) throws HopTransformException { try { - logBasic("PASO 1"); List remarks = new ArrayList<>(); RowMetaAndData rowMetaAndData = Plc4xWrite.buildRow(this, remarks, name); - logBasic("PASO 2"); - if (!remarks.isEmpty()) { - logBasic("PASO 3"); - StringBuilder stringRemarks = new StringBuilder(); - for (ICheckResult remark : remarks) { - logBasic("PASO 3x: " + remark.toString()); - stringRemarks.append(remark.toString()).append(Const.CR); + + if (!remarks.isEmpty()) { + StringBuilder stringRemarks = new StringBuilder(); + for (ICheckResult remark : remarks) { + stringRemarks.append(remark.toString()).append(Const.CR); + } + throw new HopTransformException(stringRemarks.toString()); + } + for (IValueMeta valueMeta : rowMetaAndData.getRowMeta().getValueMetaList()) { + valueMeta.setOrigin(name); } - logBasic("PASO 3.1"); - throw new HopTransformException(stringRemarks.toString()); - } - logBasic("PASO 4"); - for (IValueMeta valueMeta : rowMetaAndData.getRowMeta().getValueMetaList()) { - valueMeta.setOrigin(name); - } - logBasic("PASO 5"); - inputRowMeta.mergeRowMeta(rowMetaAndData.getRowMeta()); + + inputRowMeta.mergeRowMeta(rowMetaAndData.getRowMeta()); } catch (Exception e) { - throw new HopTransformException(e); + throw new HopTransformException(e); } } diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubs.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubs.java index 51c6c9d5366..67003bf3b5e 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubs.java +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubs.java @@ -17,13 +17,16 @@ package org.apache.plc4x.hop.transforms.plc4xsubs; +import java.time.Duration; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; import org.apache.commons.lang3.StringUtils; import org.apache.hop.core.CheckResult; import org.apache.hop.core.Const; @@ -50,32 +53,40 @@ import org.apache.hop.pipeline.transform.TransformMeta; import org.apache.plc4x.hop.metadata.Plc4xConnection; import org.apache.plc4x.hop.transforms.util.Plc4xGeneratorField; -import org.apache.plc4x.hop.transforms.util.Plc4xPlcField; +import org.apache.plc4x.hop.transforms.util.Plc4xPlcTag; +import org.apache.plc4x.hop.transforms.util.Plc4xPlcSubscriptionTag; import org.apache.plc4x.hop.transforms.util.Plc4xWrapperConnection; import org.apache.plc4x.java.DefaultPlcDriverManager; import org.apache.plc4x.java.api.PlcConnection; import org.apache.plc4x.java.api.messages.PlcReadRequest; import org.apache.plc4x.java.api.messages.PlcReadResponse; +import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent; +import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest; +import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse; +import org.apache.plc4x.java.s7.events.S7Event; /** * Transform That contains the basic skeleton needed to create your own plugin * */ -public class Plc4xSubs extends BaseTransform implements ITransform { +public class Plc4xSubs extends BaseTransform { private static final Class PKG = Plc4xSubs.class; // Needed by Translator private Plc4xConnection connmeta = null; private Plc4xWrapperConnection connwrapper = null; - private PlcReadRequest readRequest = null; - private PlcReadResponse readResponse = null; + private PlcSubscriptionRequest subsRequest = null; + private PlcSubscriptionResponse subsResponse = null; private int maxwait = 0; private static final ReentrantLock lock = new ReentrantLock(); + private ConcurrentLinkedQueue events = new ConcurrentLinkedQueue(); + private boolean stopBundle = false; + private static final String dummy = "dummy"; private Map index = new HashMap(); - private Map plcfields = new HashMap(); + private Map plctags = new HashMap(); public Plc4xSubs(TransformMeta transformMeta, Plc4xSubsMeta meta, Plc4xSubsData data, int copyNr, PipelineMeta pipelineMeta, Pipeline pipeline ) { @@ -108,7 +119,7 @@ public static final RowMetaAndData buildRow( for (Plc4xGeneratorField field : meta.getFields()) { int typeString = ValueMetaFactory.getIdForValueMeta(field.getType()); if (StringUtils.isNotEmpty(field.getType())) { - System.out.println("typeString: " + typeString); + IValueMeta valueMeta = ValueMetaFactory.createValueMeta(field.getName(), typeString); // build a // value! @@ -145,7 +156,7 @@ public static final RowMetaAndData buildRow( // Convert the data from String to the specified type ... // try { - System.out.println("stringValue: " + stringValue); + rowData[index] = valueMeta.convertData(stringMeta, stringValue); } catch (HopValueException e) { switch (valueMeta.getType()) { @@ -252,11 +263,11 @@ public boolean processRow() throws HopException { if (first) { index.clear(); - plcfields.clear(); + plctags.clear(); //This performs a minimal check on the user item. //It guarantees that the rates are within those managed by Plc4x. meta.getFields().forEach((f) ->{ - plcfields.put(f.getName(),Plc4xPlcField.of(f.getItem())); + plctags.put(f.getName(),Plc4xPlcSubscriptionTag.of(f.getItem())); }); first = false; } @@ -266,6 +277,7 @@ public boolean processRow() throws HopException { IHopMetadataProvider metaprovider = getMetadataProvider(); connmeta = metaprovider.getSerializer(Plc4xConnection.class).load(meta.getConnection()); if (connwrapper == null) { + System.out.println("PASO 02"); connwrapper = (Plc4xWrapperConnection) getPipeline().getExtensionDataMap().get(meta.getConnection()); //(02) if (connwrapper != null) connwrapper.retain(); }; @@ -279,7 +291,7 @@ public boolean processRow() throws HopException { } if ((connmeta != null) && (connwrapper == null)){ - readRequest = null; + subsRequest = null; try{ PlcConnection conn = new DefaultPlcDriverManager().getConnection(connmeta.getUrl()); //(03) if (conn.isConnected()) { @@ -297,24 +309,28 @@ public boolean processRow() throws HopException { if ((connmeta != null) && (connwrapper != null)){ if (connwrapper.getConnection().isConnected()){ - if (readRequest == null){ - PlcReadRequest.Builder builder = connwrapper.getConnection().readRequestBuilder(); //(05) + if (subsRequest == null){ + PlcSubscriptionRequest.Builder builder = connwrapper.getConnection().subscriptionRequestBuilder(); //(05) for (Plc4xGeneratorField field: meta.getFields()){ - builder.addTagAddress(field.getName(), field.getItem()); + System.out.println(field.getName() + " : " + field.getItem().toString()); + builder.addCyclicTagAddress(field.getName(), field.getItem().toString(), Duration.ofMillis(1000)); } - readRequest = builder.build(); + System.out.println("PASO: 05"); + subsRequest = builder.build(); } try { maxwait = Integer.parseInt(meta.getMaxwaitInMs()); - maxwait = (maxwait<100)?100:maxwait; - readResponse = readRequest.execute().get(maxwait, TimeUnit.MILLISECONDS); - - for (Plc4xGeneratorField field: meta.getFields()){ - field.setValue(readResponse.getString(field.getName())); - } + maxwait = (maxwait<1000)?1000:maxwait; + System.out.println("PASO: 06"); + subsResponse = subsRequest.execute().get(); + System.out.println("PASO: 07"); + //Only for Siemens S7 + subsResponse.getSubscriptionHandles().forEach(a -> a.register(e -> events.add(e))); + System.out.println("PASO: 08"); } catch (Exception ex) { setErrors(1L); logError("Unable read from PLC. " + ex.getMessage()); + ex.printStackTrace(); } } else { @@ -332,17 +348,23 @@ public boolean processRow() throws HopException { } // - int interval = Integer.parseInt(meta.getIntervalInMs()); + while (events.size() == 0) { + try { + Thread.sleep(100); + if (stopBundle) { + setOutputDone(); // signal end to receiver(s) + return false; + } + } catch (InterruptedException ex) { + break; + } + } - try { - Thread.sleep(interval); - } catch (InterruptedException ex) { - setErrors(1L); - logError(ex.getMessage()); - } + PlcSubscriptionEvent s7event = events.poll(); + System.out.println("Ejecuto el consumidor en el cliente..." + s7event.getTagNames()); r = data.outputRowMeta.cloneRow(data.outputRowData); - logBasic("Tamano de los datos: " + r.length); + data.prevDate = data.rowDate; data.rowDate = new Date(); int index = 0; @@ -435,12 +457,16 @@ public void dispose() { getPipeline().getExtensionDataMap().remove(meta.getConnection()); } connwrapper = null; - readRequest = null; - + subsRequest = null; } } - + + @Override + public void stopRunning() throws HopException { + super.stopRunning(); + stopBundle = true; + } } diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsMeta.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsMeta.java index 35f15665bdb..12943301d71 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsMeta.java +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/plc4xsubs/Plc4xSubsMeta.java @@ -54,7 +54,7 @@ categoryDescription = "i18n:org.apache.plc4x.hop.transforms.plc4xinput:Plc4x.Category.plc4x", documentationUrl = "https://plc4x.apache.org/users/integrations/apache-calcite.html" ) -public class Plc4xSubsMeta extends BaseTransformMeta implements ITransformMeta { +public class Plc4xSubsMeta extends BaseTransformMeta{ private static final Class PKG = Plc4xSubsMeta.class; // Needed by Translator @@ -136,28 +136,24 @@ public Plc4xSubsMeta clone() { public void getFields( IRowMeta inputRowMeta, String name, IRowMeta[] info, TransformMeta nextTransform, IVariables variables, IHopMetadataProvider metadataProvider ) throws HopTransformException { try { - logBasic("PASO 1"); List remarks = new ArrayList<>(); RowMetaAndData rowMetaAndData = Plc4xSubs.buildRow(this, remarks, name); - logBasic("PASO 2"); - if (!remarks.isEmpty()) { - logBasic("PASO 3"); - StringBuilder stringRemarks = new StringBuilder(); - for (ICheckResult remark : remarks) { - logBasic("PASO 3x: " + remark.toString()); - stringRemarks.append(remark.toString()).append(Const.CR); + + if (!remarks.isEmpty()) { + StringBuilder stringRemarks = new StringBuilder(); + for (ICheckResult remark : remarks) { + stringRemarks.append(remark.toString()).append(Const.CR); + } + throw new HopTransformException(stringRemarks.toString()); + } + + for (IValueMeta valueMeta : rowMetaAndData.getRowMeta().getValueMetaList()) { + valueMeta.setOrigin(name); } - logBasic("PASO 3.1"); - throw new HopTransformException(stringRemarks.toString()); - } - logBasic("PASO 4"); - for (IValueMeta valueMeta : rowMetaAndData.getRowMeta().getValueMetaList()) { - valueMeta.setOrigin(name); - } - logBasic("PASO 5"); - inputRowMeta.mergeRowMeta(rowMetaAndData.getRowMeta()); + + inputRowMeta.mergeRowMeta(rowMetaAndData.getRowMeta()); } catch (Exception e) { - throw new HopTransformException(e); + throw new HopTransformException(e); } } diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcSubscriptionTag.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcSubscriptionTag.java new file mode 100644 index 00000000000..2a261a39062 --- /dev/null +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcSubscriptionTag.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.plc4x.hop.transforms.util; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import java.time.Duration; +import org.apache.plc4x.java.api.exceptions.PlcInvalidTagException; +import org.apache.plc4x.java.api.model.PlcSubscriptionTag; +import org.apache.plc4x.java.spi.generation.SerializationException; +import org.apache.plc4x.java.spi.generation.WriteBuffer; +import org.apache.plc4x.java.spi.utils.Serializable; + +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.plc4x.java.api.model.PlcTag; +import org.apache.plc4x.java.api.types.PlcSubscriptionType; + +/* +* Code taken from the Modbus driver implementation. +* This allows me to make the correct interpretation of the "Hop" values +* towards the writing fields. +* +* TODO: The HOP interpreter generates an error when processing +* the "Integer" fields. +*/ + +public class Plc4xPlcSubscriptionTag implements PlcTag, Serializable { + + public static final Pattern ADDRESS_PATTERN = Pattern.compile("(?
[\\%a-zA-Z_\\.0-9]+)(:(?[a-zA-Z_]+))?(\\[(?\\d+)])?"); + + protected static final int PROTOCOL_ADDRESS_OFFSET = 1; + + private final String address; + + private final int quantity; + + private final Plc4xDataType dataType; + + public static Plc4xPlcSubscriptionTag of(String addressString) { + if (Plc4xPlcSubscriptionTag.matches(addressString)) { + Matcher matcher = ADDRESS_PATTERN.matcher(addressString); + + matcher.matches(); + + String address = matcher.group("address"); + + String quantityString = matcher.group("quantity"); + int quantity = quantityString != null ? Integer.parseInt(quantityString) : 1; + + Plc4xDataType dataType = (matcher.group("datatype") != null) ? Plc4xDataType.valueOf(matcher.group("datatype")) : Plc4xDataType.BOOL; + + + return new Plc4xPlcSubscriptionTag(address, quantity, dataType); + } + + throw new PlcInvalidTagException("Unable to parse address: " + addressString); + } + + protected Plc4xPlcSubscriptionTag(String address, Integer quantity, Plc4xDataType dataType) { + this.address = address; + + this.quantity = quantity != null ? quantity : 1; + + this.dataType = dataType != null ? dataType : Plc4xDataType.INT; + } + + public static boolean matches(String addressString) { + return ADDRESS_PATTERN.matcher(addressString).matches(); + } + + public String getAddress() { + return address; + } + + public int getNumberOfElements() { + return quantity; + } + + public int getLengthBytes() { + return quantity * dataType.getDataTypeSize(); + } + + @JsonIgnore + public int getLengthWords() { + return (int) ((quantity * (float) dataType.getDataTypeSize()) / 2.0f); + } + + public Plc4xDataType getDataType() { + return dataType; + } + + public String getPlcDataType() { + return dataType.name(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Plc4xPlcSubscriptionTag)) { + return false; + } + Plc4xPlcSubscriptionTag that = (Plc4xPlcSubscriptionTag) o; + return address == that.address; + } + + @Override + public int hashCode() { + return Objects.hash(address); + } + + @Override + public String toString() { + return "Plc4xPlcSubscriptionField{" + + " address=" + address + + " datatype=" + dataType + + " quantity=" + quantity + + " }"; + } + + @Override + public void serialize(WriteBuffer wb) throws SerializationException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getAddressString() { + throw new UnsupportedOperationException("Not supported yet."); + } + +// @Override +// public PlcSubscriptionType getPlcSubscriptionType() { +// throw new UnsupportedOperationException("Not supported yet."); +// } +// +// @Override +// public Optional getDuration() { +// throw new UnsupportedOperationException("Not supported yet."); +// } + +} diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcField.java b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcTag.java similarity index 85% rename from plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcField.java rename to plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcTag.java index 295dc9f1765..d89cbfabc73 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcField.java +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/java/org/apache/plc4x/hop/transforms/util/Plc4xPlcTag.java @@ -21,12 +21,10 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import org.apache.plc4x.java.api.exceptions.PlcInvalidTagException; import org.apache.plc4x.java.api.model.PlcTag; -import org.apache.plc4x.java.spi.generation.ParseException; import org.apache.plc4x.java.spi.generation.SerializationException; import org.apache.plc4x.java.spi.generation.WriteBuffer; import org.apache.plc4x.java.spi.utils.Serializable; -import java.nio.charset.StandardCharsets; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -40,7 +38,7 @@ * the "Integer" fields. */ -public class Plc4xPlcField implements PlcTag, Serializable { +public class Plc4xPlcTag implements PlcTag, Serializable { public static final Pattern ADDRESS_PATTERN = Pattern.compile("(?
[\\%a-zA-Z_\\.0-9]+)(:(?[a-zA-Z_]+))?(\\[(?\\d+)])?"); @@ -52,8 +50,8 @@ public class Plc4xPlcField implements PlcTag, Serializable { private final Plc4xDataType dataType; - public static Plc4xPlcField of(String addressString) { - if (Plc4xPlcField.matches(addressString)) { + public static Plc4xPlcTag of(String addressString) { + if (Plc4xPlcTag.matches(addressString)) { Matcher matcher = ADDRESS_PATTERN.matcher(addressString); matcher.matches(); @@ -66,13 +64,13 @@ public static Plc4xPlcField of(String addressString) { Plc4xDataType dataType = (matcher.group("datatype") != null) ? Plc4xDataType.valueOf(matcher.group("datatype")) : Plc4xDataType.BOOL; - return new Plc4xPlcField(address, quantity, dataType); + return new Plc4xPlcTag(address, quantity, dataType); } throw new PlcInvalidTagException("Unable to parse address: " + addressString); } - protected Plc4xPlcField(String address, Integer quantity, Plc4xDataType dataType) { + protected Plc4xPlcTag(String address, Integer quantity, Plc4xDataType dataType) { this.address = address; this.quantity = quantity != null ? quantity : 1; @@ -114,10 +112,10 @@ public boolean equals(Object o) { if (this == o) { return true; } - if (!(o instanceof Plc4xPlcField)) { + if (!(o instanceof Plc4xPlcTag)) { return false; } - Plc4xPlcField that = (Plc4xPlcField) o; + Plc4xPlcTag that = (Plc4xPlcTag) o; return address == that.address; } @@ -137,12 +135,12 @@ public String toString() { @Override public void serialize(WriteBuffer wb) throws SerializationException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public String getAddressString() { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + throw new UnsupportedOperationException("Not supported yet."); } } diff --git a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xevent/messages/messages_en_US.properties b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xevent/messages/messages_en_US.properties index b6bc8d9f8d5..70a5e66f92e 100644 --- a/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xevent/messages/messages_en_US.properties +++ b/plc4j/integrations/apache-hop/plc4x-hop-transformer/src/main/resources/org/apache/plc4x/hop/transforms/plc4xevent/messages/messages_en_US.properties @@ -21,7 +21,7 @@ Plc4x.Read.Description=Plc4x Event Transform Description Plc4x.Read.Shell.Title=Plc4x Event Transform Title Plc4x.Read.TransformName.Label=Plc4x Event Sample Name -Plc4x.Read.Meta.Injection.NeverEnding=Connection +Plc4x.Read.Meta.Injection.Connection=Connection Plc4x.Read.Meta.Injection.NeverEnding=Nerverending Plc4x.Read.Meta.Injection.MaxwaitInMs=MaxwaitIn Plc4x.Read.Meta.Injection.IntervalInMs=IntervalIn @@ -30,6 +30,11 @@ Plc4x.Read.Meta.Injection.LastTimeField=LastTimeField Plc4x.Read.Meta.Injection.RowLimit=RowLimit Plc4x.Read.Meta.Injection.Fields=Fields +Plc4x.Read.Meta.Injection.ModeEvent=ModeEvent +Plc4x.Read.Meta.Injection.UserEvent=UserEvent +Plc4x.Read.Meta.Injection.SysEvent=SysEvent +Plc4x.Read.Meta.Injection.AlarmEvent=AlarmEvent + Plc4x.Read.Meta.Injection.Field.Name=Name Plc4x.Read.Meta.Injection.Field.Item=Item Plc4x.Read.Meta.Injection.Field.Type=Type @@ -47,6 +52,13 @@ Plc4x.Read.Meta.Dialog.Settings.Title=Dialog Plc4x.Read.Meta.Dialog.DialogTitle=Plc4x Read transformer Plc4x.Read.Meta.Dialog.Limit.Label=Limit Plc4x.Read.Meta.Dialog.NeverEnding.Label=Never ending + +Plc4x.Read.Meta.Dialog.ModeEvent.Label=Mode event +Plc4x.Read.Meta.Dialog.UserEvent.Label=User event +Plc4x.Read.Meta.Dialog.SysEvent.Label=Sys event +Plc4x.Read.Meta.Dialog.UserEvent.Label=User event +Plc4x.Read.Meta.Dialog.AlarmEvent.Label=Alarm event + Plc4x.Read.Meta.Dialog.Maxwait.Label=Max waiting Plc4x.Read.Meta.Dialog.Interval.Label=Interval Plc4x.Read.Meta.Dialog.RowTimeField.Label=Time diff --git a/pom.xml b/pom.xml index 4e114e4089c..324c0f7ded2 100644 --- a/pom.xml +++ b/pom.xml @@ -818,6 +818,8 @@ **/hs_err_pid* **/replay_pid* + + **/*.svg diff --git a/src/site/asciidoc/index.adoc b/src/site/asciidoc/index.adoc index 5ecb4db6614..cbed626f264 100644 --- a/src/site/asciidoc/index.adoc +++ b/src/site/asciidoc/index.adoc @@ -165,6 +165,20 @@ +