Skip to main content
Jump to: navigation, search

BaSyx / Introductory Examples / Java / Example 2

Example 2 - Remote VAB Access

In this example, the code of the previous example will be extended. The model will locally be deployed on a server and registered at the VABRegistry. Next, on the remote side, the model path is retrieved from the registry and the connection to the model is established. Finally, the same control loop as in Example 1 is implemented. As supporting component, the VABDirectoryServlet is used.

Example Code

Since the model is now potentially deployed on a separate compute node, in the following it is distinguished between the local and the remote side.

Local

The previously in Example 1 defined model is made available on a HTTP REST interface by the means of the VAB. This is done by wrapping the provider in a Servlet and providing it via e.g. an Apache Tomcat server. To enable clients to connect to this model, it is registered at the VABRegistry.

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

Remote

The remote side connects to the provided model. This is done by first retrieving the path of the model and then using it to connect to the model. Next, the control loop is implemented. Since the VAB abstracts from the location of the accessed model, the code for the control loop is equivalent to the code from Example 1.

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


Expected Output

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

Local

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

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

15:16:32.251 [main] INFO  i.Scenario2 - Created a servlet for the oven model
15:16:32.253 [main] INFO  i.Scenario2 - Oven model registered!
15:16:32.253 [main] INFO  i.Scenario2 - Created a servlet for the directory
...
15:16:32.730 [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:16:50.794 [main] INFO  i.Scenario2Connected - Current temperature: 20.0
15:16:50.945 [main] INFO  i.Scenario2Connected - Current temperature: 25.7
15:16:51.053 [main] INFO  i.Scenario2Connected - Current temperature: 28.13
15:16:51.162 [main] INFO  i.Scenario2Connected - Current temperature: 30.317
15:16:51.271 [main] INFO  i.Scenario2Connected - Current temperature: 32.2853
15:16:51.381 [main] INFO  i.Scenario2Connected - Current temperature: 34.05677
15:16:51.489 [main] INFO  i.Scenario2Connected - Current temperature: 35.651093
15:16:51.599 [main] INFO  i.Scenario2Connected - Current temperature: 37.08598370000001
15:16:51.708 [main] INFO  i.Scenario2Connected - Current temperature: 38.37738533000001
15:16:51.817 [main] INFO  i.Scenario2Connected - Current temperature: 39.53964679700001
15:16:51.925 [main] INFO  i.Scenario2Connected - Current temperature: 40.58568211730001
15:16:52.032 [main] INFO  i.Scenario2Connected - Current temperature: 38.52711390557001
15:16:52.141 [main] INFO  i.Scenario2Connected - Current temperature: 36.674402515013014
15:16:52.251 [main] INFO  i.Scenario2Connected - Current temperature: 35.00696226351172
...

Back to the top