| /******************************************************************************* |
| * Copyright (c) 2020 DFKI. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * DFKI - Volkan Gezer <volkan.gezer@dfki.de> |
| * |
| *******************************************************************************/ |
| package org.eclipse.aas.basyx.codegen.util; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| import org.eclipse.aas.basyx.codegen.util.submodel.SubModel; |
| import org.eclipse.aas.basyx.codegen.util.submodel.SubModelCreator; |
| |
| public class DataConnector { |
| private String modelUrn; |
| private String aasIp; |
| private String aasPort; |
| private SubModelCreator submodelCreator = new SubModelCreator(); |
| private Project projectOperations; |
| |
| public DataConnector(String modelUrn, String aasIp, String aasPort, SubModelCreator submodelCreator, |
| Project projectOperations) { |
| this.modelUrn = modelUrn; |
| this.aasIp = aasIp; |
| this.aasPort = aasPort; |
| this.submodelCreator = submodelCreator; |
| this.projectOperations = projectOperations; |
| } |
| |
| |
| public SubModelCreator getSubModelCreator() { |
| return submodelCreator; |
| } |
| |
| |
| public String createDataCrawler() { |
| String text = "package " + projectOperations.getNamespace() + ".connection;\r\n" + |
| "\r\n" + |
| "import java.util.Iterator;\r\n" + |
| "import java.util.Map;\r\n" + |
| "import java.util.Map.Entry;\r\n" + |
| "import java.util.concurrent.TimeUnit;\r\n" + |
| "\r\n" + |
| "import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.property.Property;\r\n" + |
| "import org.eclipse.basyx.submodel.metamodel.api.submodelelement.dataelement.IProperty;\r\n" + |
| "import org.eclipse.basyx.submodel.metamodel.map.SubModel;\r\n" + |
| "\r\n" + |
| "/**\r\n" + |
| " * The CyclicDataCrawler provides methods for collecting data from connected\r\n" + |
| " * devices and updates them into selected submodel.\r\n" + |
| " * \r\n" + |
| " * By default one cycle will always be executed.\r\n" + |
| " *\r\n" + |
| " * @author DFKI\r\n" + |
| " *\r\n" + |
| " */\r\n" + |
| " \r\n" + |
| "public class DataCrawler {\r\n" + |
| "\r\n" + |
| " protected Integer cycleCounter = 1;\r\n" + |
| " protected Integer sleepInterval = 10;\r\n" + |
| " protected ConnectedDevice connectedDevice;\r\n" + |
| " protected String aas_submodelid;\r\n" + |
| "\r\n" + |
| " public DataCrawler(ConnectedDevice connDev) {\r\n" + |
| " connectedDevice = connDev;\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " public void setCycleConfiguration(Integer cc, Integer si) {\r\n" + |
| " cycleCounter = cc;\r\n" + |
| " sleepInterval = si;\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " public void collectOPCUAData(SubModel subModel) throws Exception {\r\n" + |
| "\r\n" + |
| " for (int i = 0; i < cycleCounter; i++) {\r\n" + |
| "\r\n" + |
| " String valueupdate = \"0\";\r\n" + |
| "\r\n" + |
| " aas_submodelid = subModel.getIdShort();\r\n" + |
| "\r\n" + |
| " System.out.println(\"Activated data crawler for submodel: \" + aas_submodelid);\r\n" + |
| "\r\n" + |
| " /* Take all submodel properties in a map to provide several iterations. */\r\n" + |
| "\r\n" + |
| " Map<String, IProperty> propertyMap = subModel.getProperties();\r\n" + |
| "\r\n" + |
| " Iterator<Entry<String, IProperty>> it = propertyMap.entrySet().iterator();\r\n" + |
| "\r\n" + |
| " while (it.hasNext()) {\r\n" + |
| " Entry<String, IProperty> pair = it.next();" + |
| "\r\n" + |
| " Property propertyupdate = (Property) propertyMap.get(pair.getKey());\r\n" + |
| "\r\n" + |
| " /* Get current values from device by using the aas-key. */\r\n" + |
| "\r\n" + |
| " if (connectedDevice.online == true) {\r\n" + |
| "\r\n" + |
| " valueupdate = connectedDevice.getSingleDeviceValueByConfig(String.valueOf(pair.getKey()));\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " else {\r\n" + |
| " valueupdate = String.valueOf(i);\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " /* Updating the current available submodel. */\r\n" + |
| "\r\n" + |
| " propertyupdate.set(valueupdate);\r\n" + |
| " subModel.getProperties().replace(String.valueOf(pair.getKey()), propertyupdate);\r\n" + |
| "\r\n" + |
| " System.out.println(\"Property-Update: \" + String.valueOf(pair.getKey()) + \" with value \"\r\n" + |
| " + String.valueOf(valueupdate));\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " Thread.sleep(TimeUnit.SECONDS.toMillis(sleepInterval));\r\n" + |
| "\r\n" + |
| " System.out.println(\"Processed cycles: \" + String.valueOf(i));\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| "}\r\n" + |
| ""; |
| |
| return text; |
| } |
| |
| public String createDeviceAAS() { |
| String text = |
| "package " + projectOperations.getNamespace() + ".module.submodel;\r\n" + |
| "\r\n" + |
| "import org.eclipse.basyx.aas.metamodel.map.AssetAdministrationShell;\r\n" + |
| "import org.eclipse.basyx.aas.metamodel.map.descriptor.ModelUrn;\r\n" + |
| "\r\n" + |
| "/**\r\n" + |
| " * AAS header element for inputs of a floor device.\r\n" + |
| " * \r\n" + |
| " * @author DFKI\r\n" + |
| " * \r\n" + |
| " */\r\n" + |
| "\r\n" + |
| "public class DeviceAAS extends AssetAdministrationShell {\r\n" + |
| " private static final long serialVersionUID = 1L;\r\n" + |
| "\r\n" + |
| " // Since submodel-class refactoring, reference of inherited submodels necessary\r\n" + |
| " // in the aas class is no longer necessary.\r\n" + |
| "\r\n" + |
| " public DeviceAAS() {\r\n" + |
| "\r\n" + |
| " // Model URN only available as placeholder\r\n" + |
| "\r\n" + |
| " ModelUrn urn = new ModelUrn(\"" + this.modelUrn + "\");\r\n" + |
| " this.setIdentification(urn.getIdType(), urn.getURN());\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "}"; |
| |
| return text; |
| } |
| |
| public String createConnectedDevice() { |
| return createConnectedDevice("", "", "", "", "", ""); |
| } |
| |
| public String createConnectedDevice(String sqlHostPort, String sqlDb, String sqlUser, String sqlPass, String sqlP, String sqlD) { |
| String text = "package " + projectOperations.getNamespace() + ".connection;\r\n" + |
| "\r\n" + |
| "import java.sql.ResultSet;\r\n" + |
| "import java.util.Arrays;\r\n" + |
| "import java.util.Collection;\r\n" + |
| "import java.util.LinkedList;\r\n" + |
| "\r\n" + |
| "import org.eclipse.basyx.tools.sql.driver.SQLDriver;\r\n" + |
| "import org.eclipse.basyx.tools.sql.driver.ISQLDriver;\r\n" + |
| "import org.eclipse.basyx.vab.gateway.ConnectorProviderMapper;\r\n" + |
| "import org.eclipse.basyx.vab.protocol.opcua.connector.OpcUaConnectorProvider;\r\n" + |
| "\r\n" + |
| "/**\r\n" + |
| " * This device (connector) class implements connector-interfaces that are not\r\n" + |
| " * yet or not strongly supported by the Virtual Automation Bus, because they\r\n" + |
| " * need a specific configuration (e.g. OPCUA / MQTT) to the control component.\r\n" + |
| " * The belonging configuration for values and methods for a specific device will\r\n" + |
| " * be done here, so the class has the role to provide this configuration.\r\n" + |
| " * \r\n" + |
| " * The Device must call this connection class by using database configuration\r\n" + |
| " * \"service registry\". The address can be saved in database tables for dynamic\r\n" + |
| " * endpoint calls.\r\n" + |
| " * \r\n" + |
| " * In future development, the usage of subscriptions and dependency injection\r\n" + |
| " * for class tests and simulation methods can be made. The connection type can\r\n" + |
| " * be set in an array object, to provide one or more connection types for one\r\n" + |
| " * single device.\r\n" + |
| " * \r\n" + |
| " * The provided connection types for a device has to be set up in a object\r\n" + |
| " * array, containing the connectors which can be saved in a database. Current\r\n" + |
| " * available is only OPCUA.\r\n" + |
| " * \r\n" + |
| " * @author DFKI\r\n" + |
| " *\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| "\r\n" + |
| "public class ConnectedDevice {\r\n" + |
| "\r\n" + |
| " /* Definition of objects */\r\n" + |
| "\r\n" + |
| " public ConnectorProviderMapper clientMapper = new ConnectorProviderMapper();\r\n" + |
| " public OPCUAConnectorWrapper opcuaConnector = new OPCUAConnectorWrapper();\r\n" + |
| " private static String sqlHostPort = \"" + sqlHostPort + "\";\r\n" + |
| " private static String sqlDb = \"" + sqlDb + "\";\r\n" + |
| " private static String sqlUser = \"" + sqlUser + "\";\r\n" + |
| " private static String sqlPass = \"" + sqlPass + "\";\r\n" + |
| " private static String connP = \"" + sqlP + "\";\r\n" + |
| " private static String sqlD = \"" + sqlD + "\";\r\n" + |
| " \r\n" + |
| " /* Definition of properties */\r\n" + |
| "\r\n" + |
| " protected String devendpoint;\r\n" + |
| " protected String deviceid;\r\n" + |
| " protected String address;\r\n" + |
| " protected Object[] connectiontype;\r\n" + |
| " protected Boolean databaseinit = false;\r\n" + |
| " public Boolean online = false;\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Store SQL driver reference\r\n" + |
| " */\r\n" + |
| " \r\n" + |
| " protected ISQLDriver sqlDriver = null;\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * The Device-Class should contain the adapters for different communication\r\n" + |
| " * protocols. Initialization e.g. of the connector object for OPC UA.\r\n" + |
| " */\r\n" + |
| " \r\n" + |
| " public ConnectedDevice(String endpoint, Object[] conntypes, String devid, Boolean initDB) {\r\n" + |
| " this(endpoint, conntypes, devid, initDB, ConnectedDevice.sqlHostPort, ConnectedDevice.sqlDb, ConnectedDevice.sqlUser, ConnectedDevice.sqlPass, \r\n" + |
| " ConnectedDevice.connP, ConnectedDevice.sqlD);\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " public ConnectedDevice(String endpoint, Object[] conntypes, String devid, Boolean initDB,\r\n" + |
| " String sqlHostPort, String sqlDb, String sqlUser, String sqlPass, String sqlConnectP, String sqlDr) {\r\n" + |
| " \r\n" + |
| " ConnectedDevice.sqlHostPort = sqlHostPort;\r\n" + |
| " ConnectedDevice.sqlDb = sqlDb;\r\n" + |
| " ConnectedDevice.sqlUser = sqlUser;\r\n" + |
| " ConnectedDevice.sqlPass = sqlPass;\r\n" + |
| " ConnectedDevice.connP = sqlConnectP;\r\n" + |
| " ConnectedDevice.sqlD = sqlDr;\r\n" + |
| " \r\n" + |
| "\r\n" + |
| " devendpoint = endpoint;\r\n" + |
| " deviceid = devid;\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Set the connection type and initialize all necessary connector wrappers.\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " connectiontype = conntypes;\r\n" + |
| "\r\n" + |
| " if (connectiontype[0] == \"OPCUA\") {\r\n" + |
| " opcuaConnector.clientMapper.addConnectorProvider(\"opc.tcp\", new OpcUaConnectorProvider());\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Set the connection to database to enable interactions with available\r\n" + |
| " * configuration.\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " if (initDB == true) {\r\n" + |
| " sqlDriver = new SQLDriver(sqlHostPort + \"/\" + sqlDb, sqlUser, sqlPass, sqlConnectP,\r\n" + |
| " sqlDr);\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " /**\r\n" + |
| " * Method getSingleDeviceValueByConfig uses a key to identify the configuration\r\n" + |
| " * \r\n" + |
| " * @param key identifier of element\r\n" + |
| " * \r\n" + |
| " * @return device value\r\n" + |
| " * \r\n" + |
| " */\r\n" + |
| " \r\n" + |
| " public String getSingleDeviceValueByConfig(String key) throws Exception {\r\n" + |
| "\r\n" + |
| " String address;\r\n" + |
| "\r\n" + |
| " if (sqlDriver == null) {\r\n" + |
| " return \"No Database initialized\";\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Set the SQL connection parameters\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " Collection<String> sqlQuery1Params = new LinkedList<>();\r\n" + |
| "\r\n" + |
| " sqlQuery1Params.add(\"deviceid\");\r\n" + |
| " sqlQuery1Params.add(deviceid);\r\n" + |
| " sqlQuery1Params.add(\"browsename\");\r\n" + |
| " sqlQuery1Params.add(key);\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Set the SQL connection string\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " String sqlQuery1String = getSQLString(\"SELECT * FROM device.deviceendpoints WHERE $1='$2' AND $3='$4'\",\r\n" + |
| " sqlQuery1Params);\r\n" + |
| "\r\n" + |
| " System.out.println(\"SQL: \" + sqlQuery1String);\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Get the address as SQL result string\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " ResultSet result1 = sqlDriver.sqlQuery(sqlQuery1String);\r\n" + |
| "\r\n" + |
| " /* Result next necessary to guarantee a data entry */\r\n" + |
| "\r\n" + |
| " if (result1.next()) {\r\n" + |
| "\r\n" + |
| " address = result1.getString(\"address\");\r\n" + |
| "\r\n" + |
| " System.out.println(\"ID : \" + address);\r\n" + |
| " return this.getSingleDeviceValue(address, \"OPCUA\");\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " return \"No configuration records available\";\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " /**\r\n" + |
| " * Method getSingleDeviceValue uses address call for the set connector\r\n" + |
| " * \r\n" + |
| " * @param address path of connection endpoint (e.g. opcua node)\r\n" + |
| " * @param conntype the connection type to access the endpoint\r\n" + |
| " * \r\n" + |
| " * @return Device value\r\n" + |
| " * \r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " public String getSingleDeviceValue(String address, String conntype) throws Exception {\r\n" + |
| "\r\n" + |
| " try {\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Execute only, if device can provide the configured connection type for the\r\n" + |
| " * address.\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " if (Arrays.stream(connectiontype).anyMatch(x -> conntype.equals(x))) {\r\n" + |
| "\r\n" + |
| " Object ret = (opcuaConnector.getOPCUANodeValue(devendpoint, address));\r\n" + |
| "\r\n" + |
| " return (String) ret;\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " return null;\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " catch (Exception e) {\r\n" + |
| " e.printStackTrace();\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " return null;\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " /**\r\n" + |
| " * Method setSingleDeviceValueByConfig uses a key to identify the configuration\r\n" + |
| " * \r\n" + |
| " * @param key identifier of element\r\n" + |
| " * @param value value that should be set\r\n" + |
| " * \r\n" + |
| " * @return device value\r\n" + |
| " * \r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " public String setSingleDeviceValueByConfig(String key, String value) throws Exception {\r\n" + |
| "\r\n" + |
| " String address;\r\n" + |
| "\r\n" + |
| " if (sqlDriver == null) {\r\n" + |
| " return \"No Database initialized\";\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Set the SQL connection parameters\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " Collection<String> sqlQuery1Params = new LinkedList<>();\r\n" + |
| "\r\n" + |
| " sqlQuery1Params.add(\"deviceid\");\r\n" + |
| " sqlQuery1Params.add(deviceid);\r\n" + |
| " sqlQuery1Params.add(\"browsename\");\r\n" + |
| " sqlQuery1Params.add(key);\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Set the SQL connection string\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " String sqlQuery1String = getSQLString(\"SELECT * FROM device.deviceendpoints WHERE $1='$2' AND $3='$4'\",\r\n" + |
| " sqlQuery1Params);\r\n" + |
| "\r\n" + |
| " System.out.println(\"SQL: \" + sqlQuery1String);\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Get the address as SQL result string\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " ResultSet result1 = sqlDriver.sqlQuery(sqlQuery1String);\r\n" + |
| "\r\n" + |
| " /* Result next necessary to guarantee a data entry */\r\n" + |
| "\r\n" + |
| " if (result1.next()) {\r\n" + |
| "\r\n" + |
| " address = result1.getString(\"address\");\r\n" + |
| "\r\n" + |
| " System.out.println(\"ID : \" + address);\r\n" + |
| " return this.setSingleDeviceValue(address, \"OPCUA\", value);\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " return \"No configuration records available\";\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " /**\r\n" + |
| " * Method setSingleDeviceValue uses address call for the set connector\r\n" + |
| " * \r\n" + |
| " * @param address path of connection endpoint (e.g. opcua node)\r\n" + |
| " * @param conntype the connection type to access the endpoint\r\n" + |
| " * @param value value that should be set\r\n" + |
| " * \r\n" + |
| " * @return device value\r\n" + |
| " * \r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " public String setSingleDeviceValue(String address, String conntype, String value) throws Exception {\r\n" + |
| "\r\n" + |
| " try {\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Execute only, if device can provide the configured connection type for the\r\n" + |
| " * address.\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " if (Arrays.stream(connectiontype).anyMatch(x -> conntype.equals(x))) {\r\n" + |
| "\r\n" + |
| " Object ret = (opcuaConnector.setOPCUANodeValue(devendpoint, address, value, \"Boolean\"));\r\n" + |
| "\r\n" + |
| " return (String) ret;\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " catch (Exception e) {\r\n" + |
| " e.printStackTrace();\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " return null;\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " /**\r\n" + |
| " * Method setSingleDeviceValueByConfig uses a key to identify the configuration\r\n" + |
| " * \r\n" + |
| " * @param key identifier of element\r\n" + |
| " * @param arguments[] arguments for method calls\r\n" + |
| " * \r\n" + |
| " * @return result of method call\r\n" + |
| " * \r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " public String callOperationByConfig(String key, Object[] arguments) throws Exception {\r\n" + |
| "\r\n" + |
| " String address;\r\n" + |
| "\r\n" + |
| " if (sqlDriver == null) {\r\n" + |
| " return \"No Database initialized\";\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Set the SQL connection parameters\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " Collection<String> sqlQuery1Params = new LinkedList<>();\r\n" + |
| "\r\n" + |
| " sqlQuery1Params.add(\"deviceid\");\r\n" + |
| " sqlQuery1Params.add(deviceid);\r\n" + |
| " sqlQuery1Params.add(\"browsename\");\r\n" + |
| " sqlQuery1Params.add(key);\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Set the SQL connection string\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " String sqlQuery1String = getSQLString(\"SELECT * FROM device.deviceendpoints WHERE $1='$2' AND $3='$4'\",\r\n" + |
| " sqlQuery1Params);\r\n" + |
| "\r\n" + |
| " System.out.println(\"SQL: \" + sqlQuery1String);\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Get the address as SQL result string\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " ResultSet result1 = sqlDriver.sqlQuery(sqlQuery1String);\r\n" + |
| "\r\n" + |
| " /* Result next necessary to guarantee a data entry */\r\n" + |
| "\r\n" + |
| " if (result1.next()) {\r\n" + |
| "\r\n" + |
| " address = result1.getString(\"address\");\r\n" + |
| "\r\n" + |
| " System.out.println(\"ID : \" + address);\r\n" + |
| " return this.callOperation(address, \"OPCUA\", arguments);\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " return \"No configuration records available\";\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " /**\r\n" + |
| " * Method callOperation uses address call for the set connector\r\n" + |
| " * \r\n" + |
| " * @param address path of connection endpoint (e.g. opcua node)\r\n" + |
| " * @param conntype the connection type to access the endpoint\r\n" + |
| " * @param arguments[] arguments for method calls\r\n" + |
| " * \r\n" + |
| " * @return device value\r\n" + |
| " * \r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " public String callOperation(String address, String conntype, Object[] arguments) throws Exception {\r\n" + |
| "\r\n" + |
| " try {\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Execute only, if device can provide the configured connection type for the\r\n" + |
| " * address.\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " if (Arrays.stream(connectiontype).anyMatch(x -> conntype.equals(x))) {\r\n" + |
| "\r\n" + |
| " Object ret = (opcuaConnector.callOPCUAMethod(devendpoint, address, arguments));\r\n" + |
| "\r\n" + |
| " return (String) ret;\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " catch (Exception e) {\r\n" + |
| " e.printStackTrace();\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " return null;\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " /**\r\n" + |
| " * >>> Method from class \"SQLProviderTestOLD\" <<<\r\n" + |
| " * \r\n" + |
| " * Create a SQL string from an input SQL String with place holders in format $x\r\n" + |
| " * with x being an integer number.\r\n" + |
| " * \r\n" + |
| " * @param baseString SQL string with place holders\r\n" + |
| " * @param parameter Parameter values that place holders are substituted for\r\n" + |
| " * \r\n" + |
| " * @return SQL string with parameter instead of place holders\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " public static String getSQLString(String baseString, Collection<String> parameter) {\r\n" + |
| " // Resulting SQL String\r\n" + |
| " String result = baseString;\r\n" + |
| "\r\n" + |
| " // Replace place holders with parameter\r\n" + |
| " // - Counter variable\r\n" + |
| " int counter = 1;\r\n" + |
| " // - Replace all place holders\r\n" + |
| " for (String par : parameter) {\r\n" + |
| " result = result.replace(\"$\" + counter, par);\r\n" + |
| " counter++;\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " // Return SQL string with resolved parameter\r\n" + |
| " return result;\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| "}\r\n" + |
| ""; |
| |
| return text; |
| } |
| |
| public String createOPCUAConnectorWrapper() { |
| String text = "package " + projectOperations.getNamespace() + ".connection;\r\n" + |
| "\r\n" + |
| "import org.eclipse.basyx.vab.exception.provider.ProviderException;\r\n" + |
| "import org.eclipse.basyx.vab.gateway.ConnectorProviderMapper;\r\n" + |
| "import org.eclipse.basyx.vab.protocol.opcua.connector.OpcUaConnectorProvider;\r\n" + |
| "\r\n" + |
| "/**\r\n" + |
| " * This generic connector-class provides a wrapper which holds the OPC UA\r\n" + |
| " * clientMapper object with its functions. Aim of this wrapper class is to\r\n" + |
| " * provide the OPC UA clientRunner-Functions of VAB.\r\n" + |
| " *\r\n" + |
| " * @author DFKI\r\n" + |
| " *\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| "public class OPCUAConnectorWrapper {\r\n" + |
| "\r\n" + |
| " protected boolean booleanValue;\r\n" + |
| " public ConnectorProviderMapper clientMapper = new ConnectorProviderMapper();\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Initialize the connector object for OPC UA connection directly in the\r\n" + |
| " * connector wrapper class. The clientMapper-Object provides complete OPC UA\r\n" + |
| " * client functions from MILO package.\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " public OPCUAConnectorWrapper() {\r\n" + |
| " clientMapper.addConnectorProvider(\"opc.tcp\", new OpcUaConnectorProvider());\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " public String getOPCUANodeValue(String endpoint, String node_browsename) throws ProviderException {\r\n" + |
| "\r\n" + |
| " try {\r\n" + |
| "\r\n" + |
| " Object ret = clientMapper.getConnector(endpoint).getModelPropertyValue(node_browsename);\r\n" + |
| "\r\n" + |
| " return (String) ret;\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " catch (final Exception e) {\r\n" + |
| " e.printStackTrace();\r\n" + |
| " return \"0\";\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " public String setOPCUANodeValue(String endpoint, String node_browsename, String value, String datatype)\r\n" + |
| " throws ProviderException {\r\n" + |
| "\r\n" + |
| " try {\r\n" + |
| "\r\n" + |
| " /* TBD: DataType necessary */\r\n" + |
| "\r\n" + |
| " if (datatype == \"Boolean\") {\r\n" + |
| " booleanValue = Boolean.valueOf(value);\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " /* Set the value to opcua node */\r\n" + |
| " clientMapper.getConnector(endpoint).setModelPropertyValue(node_browsename, booleanValue);\r\n" + |
| "\r\n" + |
| " /* Check if value has been set correctly */\r\n" + |
| " Object ret = clientMapper.getConnector(endpoint).getModelPropertyValue(node_browsename);\r\n" + |
| "\r\n" + |
| " return (String) ret;\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " catch (final Exception e) {\r\n" + |
| " e.printStackTrace();\r\n" + |
| " return \"0\";\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " public String callOPCUAMethod(String endpoint, String node_browsename, Object[] methodargument)\r\n" + |
| " throws ProviderException {\r\n" + |
| "\r\n" + |
| " try {\r\n" + |
| "\r\n" + |
| " /* Provide method call with import parameters (can also be empty) */\r\n" + |
| " Object methodret = clientMapper.getConnector(endpoint).invokeOperation(node_browsename, methodargument);\r\n" + |
| "\r\n" + |
| " return (String) methodret;\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " catch (Exception e) {\r\n" + |
| " e.printStackTrace();\r\n" + |
| " return null;\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| "}\r\n" + |
| ""; |
| |
| return text; |
| } |
| |
| public String createDeviceAASServer() { |
| return createDeviceAASServer(this.aasIp, this.aasPort); |
| } |
| |
| public String createDeviceAASServer(String deviceEndPoint) { |
| return createDeviceAASServer(this.aasIp, this.aasPort, deviceEndPoint); |
| } |
| |
| public String createDeviceAASServer(String aasIp, String aasPort) { |
| return createDeviceAASServer(aasIp, aasPort, ""); |
| } |
| |
| public String createDeviceAASServer(String aasIp, String aasPort, String deviceEndPoint) { |
| // Endpoint def: opc.tcp://192.168.0.37:4840 |
| String text = "package " + projectOperations.getNamespace() + ".module;\r\n" + |
| "\r\n" + |
| "import java.util.concurrent.TimeUnit;\r\n" + |
| "\r\n" + |
| "import org.eclipse.basyx.aas.metamodel.map.AssetAdministrationShell;\r\n" + |
| "import " + projectOperations.getNamespace() + ".connection.ConnectedDevice;\r\n" + |
| "import org.eclipse.basyx.submodel.metamodel.connected.ConnectedSubModel;\r\n" + |
| "import org.eclipse.basyx.vab.coder.json.connector.JSONConnector;\r\n" + |
| "import org.eclipse.basyx.vab.modelprovider.VABElementProxy;\r\n" + |
| "import org.eclipse.basyx.vab.protocol.http.connector.HTTPConnector;\r\n" + |
| "import org.eclipse.basyx.vab.protocol.http.server.AASHTTPServer;\r\n" + |
| "\r\n" + |
| "/**\r\n" + |
| " * A HTTP server with the asset administration shell and registry context. This\r\n" + |
| " * class provides the AAS with submodels over HTTP by using the given context\r\n" + |
| " * and provides the connected device class for the submodel connection.\r\n" + |
| " * \r\n" + |
| " * @author DFKI\r\n" + |
| " * \r\n" + |
| " */\r\n" + |
| "\r\n" + |
| "public class DeviceAASServer extends AASHTTPServer {\r\n" + |
| "\r\n" + |
| " protected static String deviceendpoint = \"" + deviceEndPoint + "/\";\r\n" + |
| " protected static AssetAdministrationShell AAS;\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Setting the context in the constructor makes the context object with submodel\r\n" + |
| " * available.\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " public DeviceAASServer(DeviceContext DeviceContext) {\r\n" + |
| "\r\n" + |
| " super(DeviceContext);\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " public static void main(String[] args) throws Exception {\r\n" + |
| "\r\n" + |
| " /* Connected device with state machine */\r\n" + |
| "\r\n" + |
| " ConnectedDevice connectedDevice = new ConnectedDevice(deviceendpoint, new Object[] { \"OPCUA\" },\r\n" + |
| " \"canvaas\", false);\r\n" + |
| "\r\n" + |
| " /* Building the HTTP Server with the given context */\r\n" + |
| "\r\n" + |
| " DeviceContext deviceContext = new DeviceContext(\"" + aasIp + "\", " + aasPort + ", connectedDevice);\r\n" + |
| " DeviceAASServer deviceServer = new DeviceAASServer(deviceContext);\r\n" + |
| " deviceServer.start();\r\n" + |
| "\r\n" + |
| " /* Create a connected sub model */\r\n" + |
| "\r\n" + |
| " // ConnectedSubModel connectedControlSubModel = directlyConnectToSubmodelControl();\r\n" + |
| "\r\n" + |
| " System.out.println(\"Waiting to connect: 2 ms\");\r\n" + |
| " Thread.sleep(TimeUnit.SECONDS.toMillis(2));\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Setting the connected device to true to enable interactions with the device.\r\n" + |
| " * Possibility in future development to set this to false for simulation mode.\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " connectedDevice.online = true;\r\n" + |
| "\r\n" + |
| " System.out.println(\"" + projectOperations.getProjectName() + " is online at: http://" + this.aasIp + ":" + |
| this.aasPort + "/" + projectOperations.getSafeProjectName() + "/aas/\");\r\n" + |
| "\r\n" + |
| " // floorserver.shutdown();\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| "// private static ConnectedSubModel directlyConnectToSubmodelControl() {\r\n" + |
| "// VABElementProxy proxy = new VABElementProxy(\"\",\r\n" + |
| "// new JSONConnector(new HTTPConnector(\"http://" + aasIp +":" + aasPort + "/"+ projectOperations.getSafeProjectName() + "/\")));\r\n" + |
| "// return new ConnectedSubModel(proxy.getDeepProxy(\"/aas/submodels/ControlComponent/\"));\r\n" + |
| "// }\r\n" + |
| "}\r\n" + |
| ""; |
| return text; |
| } |
| |
| public String createDeviceContext() { |
| String text = "package " + projectOperations.getNamespace() + ".module;\r\n" + |
| "\r\n" + |
| "import javax.servlet.http.HttpServlet;\r\n" + |
| "\r\n" + |
| "import org.eclipse.basyx.aas.metamodel.map.AssetAdministrationShell;\r\n" + |
| "import org.eclipse.basyx.aas.metamodel.map.descriptor.ModelUrn;\r\n" + |
| "import org.eclipse.basyx.aas.restapi.AASModelProvider;\r\n" + |
| "import org.eclipse.basyx.aas.metamodel.api.parts.asset.AssetKind;\r\n" + |
| "import org.eclipse.basyx.aas.metamodel.map.parts.Asset;\r\n" + |
| "import org.eclipse.basyx.submodel.metamodel.api.identifier.IdentifierType;\r\n" + |
| "import org.eclipse.basyx.aas.restapi.VABMultiSubmodelProvider;\r\n" + |
| "import " + projectOperations.getNamespace() + ".connection.ConnectedDevice;\r\n" + |
| "import " + projectOperations.getNamespace() + ".module.submodel.DeviceAAS;\r\n"; |
| for(SubModel model : submodelCreator.getSubModels()) { |
| text += "import " + projectOperations.getNamespace() + ".module.submodel." + model.getName().replace(" ", "") + ";\r\n"; |
| } |
| text += "import org.eclipse.basyx.submodel.metamodel.map.SubModel;\r\n" + |
| "import org.eclipse.basyx.submodel.restapi.SubModelProvider;\r\n" + |
| "import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;\r\n" + |
| "import org.eclipse.basyx.vab.protocol.http.server.BaSyxContext;\r\n" + |
| "import org.eclipse.basyx.vab.protocol.http.server.VABHTTPInterface;\r\n" + |
| "\r\n" + |
| "/**\r\n" + |
| " * Context for the HTTP server. This class provides the device aas with its sub\r\n" + |
| " * models providing for http-servlets by using VAB.\r\n" + |
| " * \r\n" + |
| " * @author DFKI\r\n" + |
| " * \r\n" + |
| " */\r\n" + |
| "\r\n" + |
| "public class DeviceContext extends BaSyxContext {\r\n" + |
| " private static final long serialVersionUID = 5469957942186749451L;\r\n" + |
| "\r\n" + |
| " protected AssetAdministrationShell AAS;\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * The context class is necessary to build the whole model context of AAS and\r\n" + |
| " * provide it by HTTP.\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " public DeviceContext(String hostName, int port, ConnectedDevice connDevice) {\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * Create a context with the base path /basys.floor/*, a default server context\r\n" + |
| " * base directory (\"\") and the given host server and port. The base path must be\r\n" + |
| " * identical with hosted aas and its submodels. *\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " super(\"/" + projectOperations.getSafeProjectName() + "\", \"\", hostName, port);\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * 1. Create models. For direct method link of submodels, the submodel gets the\r\n" + |
| " * connected device.\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " AssetAdministrationShell aas = new DeviceAAS();\r\n"; |
| |
| for (SubModel model : submodelCreator.getSubModels()) { |
| String modelClass = model.getName().replaceAll(" ", ""); |
| text += " SubModel " + modelClass.toLowerCase() + " = new " + modelClass + "(connDevice);\r\n"; |
| text += "\r\n" + |
| " ModelUrn urn" + modelClass.toLowerCase() + " = new ModelUrn(\"urn:de.basyxifs:devices:" + modelClass + ":1.0:1:asset#001\");\r\n" + |
| " " + modelClass.toLowerCase() + ".setIdentification(urn" + modelClass.toLowerCase() + ".getIdType(), urn" + modelClass.toLowerCase() + ".getURN());\r\n" + |
| "\r\n"; |
| // text += " aas.addSubModel(new SubmodelDescriptor(" + modelClass.toLowerCase() + ".getIdShort(), " + modelClass.toLowerCase() + ".getIdentification(),\r\n" + |
| // " \"http://" + aasIp + ":" + aasPort + "/" + projectOperations.getSafeProjectName() + "/aas/submodels/" + modelClass + "/\")); // + sm.getIdShort()\r\n" + |
| // " \r\n"; |
| text += " aas.addSubModel(" + modelClass.toLowerCase() + ");\r\n"; |
| text += " // Access to submodel via: http://" + aasIp + ":" + aasPort + "/" + projectOperations.getSafeProjectName() + "/aas/submodels/" + modelClass + "/\r\n"; |
| } |
| |
| |
| text += " Asset asset = new Asset();\r\n" + |
| " \r\n" + |
| " /* Asset Kind can be Instance or Type */\r\n" + |
| " asset.setAssetKind(AssetKind.INSTANCE);\r\n" + |
| " asset.setIdShort(\"" + projectOperations.getProjectNameWithoutSpace() + "\");\r\n" + |
| " asset.setIdentification(IdentifierType.CUSTOM, \"" + projectOperations.getProjectNameWithoutSpace() + "1\");\r\n" + |
| "\r\n" + |
| " \r\n" + |
| " aas.setAsset(asset);\r\n" + |
| " aas.setIdShort(\"" + projectOperations.getProjectNameWithoutSpace() + "AAS\");\r\n" + |
| " /* Adding all submodels by using the submodel-descriptor functionality. */\r\n" + |
| " /*\r\n" + |
| " * 2. Wrap models in model providers\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " VABMultiSubmodelProvider provider = new VABMultiSubmodelProvider();\r\n" + |
| " provider.setAssetAdministrationShell(new AASModelProvider(aas));\r\n" + |
| "\r\n"; |
| for (SubModel model : submodelCreator.getSubModels()) { |
| String modelClass = model.getName().replaceAll(" ", ""); |
| text += " SubModelProvider " + modelClass + "Provider = new SubModelProvider(" + modelClass.toLowerCase() + ");\r\n" + |
| " provider.addSubmodel(\"" + modelClass + "\", " + modelClass + "Provider);\r\n" + |
| " \r\n"; |
| } |
| |
| text += " /*\r\n" + |
| " * 3. Create HTTP servlet for hosting with tomcat\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " HttpServlet servlet = new VABHTTPInterface<IModelProvider>(provider);\r\n" + |
| "\r\n" + |
| " /*\r\n" + |
| " * 4. Add the servlet to server context\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| "// addServletMapping(\"/*\", servlet);\r\n" + |
| "// addServletMapping(\"/SQL/*\", new SQLDirectoryServlet().withParameter(\"config\",\r\n" + |
| "// \"/WebContent/WEB-INF/config/directory/sqldirectory/directory.properties\"));\r\n" + |
| "\r\n" + |
| " addServletMapping(\"/*\", servlet);\r\n" + |
| " \r\n" + |
| " /*\r\n" + |
| " * 5. Quick provide for aas and submodel elements (Possibility: Provide\r\n" + |
| " * availability in array)\r\n" + |
| " */\r\n" + |
| "\r\n" + |
| " AAS = aas;\r\n" + |
| "\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| " public AssetAdministrationShell getAAS() {\r\n" + |
| " return AAS;\r\n" + |
| " }\r\n" + |
| "\r\n" + |
| "\r\n" + |
| "}\r\n" + |
| ""; |
| return text; |
| } |
| } |