Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

BaSyx / Introductory Examples / Java / Example 2a

Example 2a - Remote VAB Access via BaSyxTCP

This is a variant of the scenario showcased in Example 2.

Instead of accessing the oven model through HTTP/REST, BaSyxTCP is used. The registry is still accessed through HTTP/REST.

Example Code

Only small code changes are necessary to support this scenario. First, the local variant needs to be changed to provide the oven model via TCP. Then, the remote side needs to be extended to support both HTTP/REST and TCP.

Local

Instead of providing the oven through HTTP/REST, it is now provided via TCP. Thus, the oven servlet is replaced with a BaSyxTCP server. Additionally, the registry entry is updated to point to the TCP server.

  1. import java.util.Map;
  2.  
  3. import javax.servlet.http.HttpServlet;
  4.  
  5. import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
  6. import org.eclipse.basyx.vab.modelprovider.lambda.VABLambdaProvider;
  7. import org.eclipse.basyx.vab.protocol.basyx.server.BaSyxTCPServer;
  8. import org.eclipse.basyx.vab.protocol.http.server.BaSyxContext;
  9. import org.eclipse.basyx.vab.protocol.http.server.BaSyxHTTPServer;
  10. import org.eclipse.basyx.vab.protocol.http.server.VABHTTPInterface;
  11. import org.eclipse.basyx.vab.registry.api.IVABRegistryService;
  12. import org.eclipse.basyx.vab.registry.memory.VABInMemoryRegistry;
  13. import org.eclipse.basyx.vab.registry.restapi.VABRegistryModelProvider;
  14. import org.slf4j.Logger;
  15. import org.slf4j.LoggerFactory;
  16.  
  17. /** 
  18.  * Expected console output in this HandsOn:
  19.  * - the heater id
  20.  * - oven is activated and deactivated multiple times
  21.  * - temperature values between 30 and 40
  22.  */
  23. public class Scenario2TCP {
  24. 	// Initializes a logger for the output
  25. 	private static final Logger logger = LoggerFactory.getLogger(Scenario2TCP.class);
  26.  
  27. 	public static void main(String[] args) throws Exception {
  28. 		// First, a local model is created that is wrapped by a model provider (see first HandsOn)
  29. 		Map<String, Object> model = Scenario1.createMyOvenModel(new Oven());
  30. 		IModelProvider modelProvider = new VABLambdaProvider(model);
  31. 		// Up to this point, everything is known from the previous HandsOn
  32.  
  33. 		// Create a directory that can store endpoints for VAB models
  34. 		// => The directory will be published using an HTTP-REST interface
  35. 		IVABRegistryService directory = new VABInMemoryRegistry();
  36.  
  37. 		// Register the VAB model at the directory (locally in this case)
  38. 		// For this example, the endpoint will be a basyx:// endpoint instead of an http:// endpoint
  39. 		directory.addMapping("oven", "basyx://127.0.0.1:7000");
  40. 		logger.info("Oven model registered!");
  41.  
  42. 		// Similar to the IModelProvider for the local oven model, a IModelProvider for the directory is created
  43. 		IModelProvider directoryProvider = new VABRegistryModelProvider(directory);
  44.  
  45.                 // Next, this model provider is given to a HTTP servlet that gives access to the directory
  46. 		HttpServlet directoryServlet = new VABHTTPInterface<IModelProvider>(directoryProvider);
  47. 		logger.info("Created a servlet for the directory");
  48.  
  49. 		// Now, define a context to which multiple servlets can be added
  50. 		BaSyxContext context = new BaSyxContext("/handson", "", "localhost", 4001);
  51. 		// => Every servlet contained in this context is available at http://localhost:4001/handson/
  52. 		context.addServletMapping("/directory/*", directoryServlet);
  53. 		// The directory will be available at http://localhost:4001/handson/directory/
  54. 		BaSyxHTTPServer server = new BaSyxHTTPServer(context);
  55. 		// Finally, the HTTP-REST server with this context is started.
  56. 		server.start();
  57.  
  58. 		// Creates a tcp server providing the oven model on port 7000
  59. 		// Note, that this is the only difference to the previous example. The modelProvider is exactly the same
  60. 		BaSyxTCPServer<IModelProvider> tcpServer = new BaSyxTCPServer<>(modelProvider, 7000);
  61. 		tcpServer.start();
  62. 		logger.info("Server started");
  63. 	}
  64. }

Remote

Due the abstracting nature of the VAB, there's little change on the remote side. Instead of directly using the HTTPConnectorProvider, the ConnectorProviderMapper is used. It allows to provide different connectors, selected depending on the address passed to it. The ConnectorProviderMapper is initialized with http prefix for HTTP/REST and basyx prefix for TCP.

The application logic, i.e. the control of the oven based on its temperature, remains unchanged. This again showcases the capability of the VAB to enable abstraction from the specific communication mechanism used.

  1. import org.eclipse.basyx.vab.gateway.ConnectorProviderMapper;
  2. import org.eclipse.basyx.vab.manager.VABConnectionManager;
  3. import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
  4. import org.eclipse.basyx.vab.protocol.basyx.connector.BaSyxConnectorFactory;
  5. import org.eclipse.basyx.vab.protocol.http.connector.HTTPConnectorFactory;
  6. import org.eclipse.basyx.vab.registry.proxy.VABRegistryProxy;
  7. import org.slf4j.Logger;
  8. import org.slf4j.LoggerFactory;
  9.  
  10. /** 
  11.  * This is the connected site in the HandsOn. Although everything is executed locally in this HandsOn,
  12.  * the connection to the model can also be established from distributed locations in the network using this code
  13.  * (using the correct network addresses).
  14.  * 
  15.  * The additionally used protocol has to be added to the connection manager. Apart from that, the code for 
  16.  * the remote access is mostly identical to the code in the previous example, since the IModelProvider and 
  17.  * directory abstract from the underlying communication protocol. 
  18.  * 
  19.  */
  20.  
  21. public class Scenario2Connected {
  22. 	// Initializes a logger for the output
  23. 	private static final Logger logger = LoggerFactory.getLogger(Scenario2Connected.class);
  24.  
  25. 	public static void main(String[] args) throws Exception {
  26. 		// At the connected site, no direct access to the model is possible
  27. 		// Every access is done through the network infrastructure
  28.  
  29. 		// The Virtual Automation Bus hides network details to the connected site. Only the endpoint of the
  30. 		// directory has to be known:
  31. 		VABRegistryProxy directoryProxy = new VABRegistryProxy("http://localhost:4001/handson/directory/");
  32.  
  33. 		// The connection manager is responsible for resolving every connection attempt
  34. 		// For this, it needs:
  35. 		// - The directory at which all models are registered
  36. 		// - A provider for different types of network protocols (in this example, both HTTP-REST and TCPBaSyx)
  37. 		ConnectorProviderMapper mapper = new ConnectorProviderMapper();
  38. 		mapper.addConnectorProvider("http", new HTTPConnectorFactory());
  39. 		mapper.addConnectorProvider("basyx", new BaSyxConnectorFactory());
  40. 		// Thus, when creating the connectionManager, this mapper is passed in the constructor
  41. 		VABConnectionManager connectionManager = new VABConnectionManager(directoryProxy, mapper);
  42.  
  43. 		// It is now one line of code to retrieve a model provider for any registered model in the network
  44. 		IModelProvider connectedOven = connectionManager.connectToVABElement("oven");
  45.  
  46. 		// Now, implement a simple a simple bang-bang controller as it has been done in the first HandsOn
  47. 		for (int i = 0; i < 100; i++) {
  48. 			// Pause for 100ms
  49. 			Thread.sleep(100);
  50. 			// Retrieve the current temperature from the model provider
  51. 			double temperature = (double) connectedOven.getValue("/properties/temperature");
  52. 			logger.info("Current temperature: " + temperature);
  53.  
  54. 			// Turn the oven on/off, depending on the defined temperature range
  55. 			if (temperature > 40) {
  56. 				connectedOven.invokeOperation("/operations/deactivateOven");
  57. 			} else if (temperature < 30) {
  58. 				connectedOven.invokeOperation("/operations/activateOven");
  59. 			}
  60. 		}
  61. 	}
  62. }

Expected Output

You will have different outputs for the local and remote code.

Local

The output states, that the oven model has been registered. After this there will be some info (maybe in a red text color) about the BaSyx Context and HTTP server (a Tomcat server) and the message from our logger, that the server has been started.

Only if you execute the remote code the output Heater: activated and Heater: deactivated will show up.

15:35:57.279 [main] INFO  i.Scenario2TCP - Oven model registered!
15:35:57.292 [main] INFO  i.Scenario2TCP - Created a servlet for the directory
...
15:35:57.753 [main] INFO  i.Scenario2 - HTTP server started
Heater: activated
Heater: deactivated
Heater: activated
Heater: deactivated
Heater: activated
...

Remote

Once you start the remote you will only see information about the current temperature which will fluctuate between ~30 and ~40. This time the information about the activation or deactivation of the heater will be part of the output of the local code.

15:39:04.381 [main] INFO  i.Scenario2Connected - Current temperature: 20.0
15:39:04.511 [main] INFO  i.Scenario2Connected - Current temperature: 23.0
15:39:04.619 [main] INFO  i.Scenario2Connected - Current temperature: 25.7
15:39:04.729 [main] INFO  i.Scenario2Connected - Current temperature: 28.13
15:39:04.837 [main] INFO  i.Scenario2Connected - Current temperature: 30.317
15:39:04.946 [main] INFO  i.Scenario2Connected - Current temperature: 32.2853
15:39:05.055 [main] INFO  i.Scenario2Connected - Current temperature: 34.05677
15:39:05.161 [main] INFO  i.Scenario2Connected - Current temperature: 35.651093
15:39:05.271 [main] INFO  i.Scenario2Connected - Current temperature: 37.08598370000001
15:39:05.379 [main] INFO  i.Scenario2Connected - Current temperature: 38.37738533000001
15:39:05.488 [main] INFO  i.Scenario2Connected - Current temperature: 39.53964679700001
15:39:05.595 [main] INFO  i.Scenario2Connected - Current temperature: 40.58568211730001
15:39:05.703 [main] INFO  i.Scenario2Connected - Current temperature: 38.52711390557001
15:39:05.810 [main] INFO  i.Scenario2Connected - Current temperature: 36.674402515013014
15:39:05.921 [main] INFO  i.Scenario2Connected - Current temperature: 35.00696226351172
...

Back to the top