Streamlining Development with the Java Delegate Code Generator

Overview

Behavior Execution Engine provides a Java delegate code generator that can generate delegate interfaces for all of the blocks in a SysML model, class stubs for the blocks, and a delegate provider that registers the delegate module with Behavior Execution Engine at runtime. These generated files include everything that Behavior Execution Engine needs in order to connect the delegates to the SysML model, allowing you to focus on the methods that need custom implementations. In this section, you will generate delegates for the UAV mission and install them for Behavior Execution Engine to use.

This section covers the following concepts:

Figure A1: Java delegate code generation

Prerequisites

Prerequisite Description
Behavior Execution Engine Installation You must have installed Behavior Execution Engine and have the prerequisites for developing delegates for Behavior Execution Engine.
Tutorial Project

You must start this section with the delegate module project from the previous section. If you did not complete the previous section, you can use the delegate module project from the Behavior Execution Engine installation: \documentation\tutorialFiles\03\DelegateModules\UAVMissionDelegateModule, but you may still need to configure the delegate module for your environment.

You also need the UAV Mission simulation project included alongside the delegate module project: \documentation\tutorialFiles\03\DelegateModules\UAVMission.mdzip

Recommended Reading Before completing this section, you may want to read the following help topics:

Instructions

Generate the delegates

You can use the Java delegate code generator to generate interfaces and class stubs for the blocks in your SysML model, as well as a delegate provider that registers your delegate module with Behavior Execution Engine at runtime. By including the AutoDelegate annotation on these interfaces and making abstract or concrete classes, you will only need to implement the methods that need custom functionality. Behavior Execution Engine will auto-implement the rest at runtime.

  1. Open the UAVMission.mdzip project specified in the prerequisites for this section using the SysML Client.
  2. Select Code Generation.
  3. In the Select Element(s) to Generate box, ensure that the Structure box is selected to include all elements that it contains in the delegate code generation. Deselect all other options.
  4. Set the Output Location text box to the UAVMissionDelegateModule directory.
  5. Select Configure Java. Entercom.agi.moxie.tutorial.uavmission in the Base Package for Java Code text box. Leave the Class Prefix and Class Suffix properties their default values. Select Back.
  6. Select Configure Elements. Ensure that all selected elements have the Auto Delegate box checked. Set all elements to generate an Abstract Class. Select Back.
  7. Select Configure Delegate Provider. Ensure that the Generate Build Files and Generate Delegate Provider boxes are checked. Ensure all delegates are included in Select Delegate(s) to Include in the Data Provider window. Select Back.

    Because you already set up your Gradle build files in the previous section, this option will detect those build files and only generate the delegate provider and its SPI file. It will not overwrite the existing build files.

  8. Enter UAVMission in the Name of Delegate Module text box.

    Figure B1: The Java delegate code generator

  9. Click Generate, then click Ok, and then close the Java delegate code generator.
  10. You should now see the generated interfaces, classes, and delegate provider in the UAVMissionDelegateModule\src\com\agi\moxie\tutorial\uavmission directory and its subdirectories.

Examine the delegate provider and SPI file

Behavior Execution Engine uses the Service Provider Interface (SPI) file to find the delegate provider at runtime.

  • In the UAVMissionDelegateProvider class:
    • Notice the list of interfaces and classes returned by provideDescriptor(). If you add more delegates to the project later, you will need to add them to this list.
    • Notice the analysis tool controller returned by provideDescriptor(). The code generator sets this to the BuiltInAnalysisToolController, but you will replace this with the StkController when connecting to STK.
  • In the UAVMissionDelegateModule\resources\META-INF\services\com.agi.moxie.spi.DelegateProvider file.
    • Notice the file only contains the fully qualified name of the delegate provider: com.agi.moxie.tutorial.uavmission.UAVMissionDelegateProvider.

Examine an interface

In the ...\structure\UAV interface:

  • Notice the @DelegateFor("Structure::UAV") annotation. This informs Behavior Execution Engine which SysML block the Java interface corresponds to.
    • Only one class or interface may use a @DelegateFor annotation for any given block.
  • Notice the @AutoDelegateImplementation annotation. This instructs Behavior Execution Engine to implement missing SysML properties and operations at runtime.
    • For example, the processFlightPlan() SysML operation is only used as a call event, so its Java implementation does not need to do anything. Behavior Execution Engine will auto-implement the processFlightPlan() Java method with an empty body in memory at runtime.

Examine a class

In the ...\structure\impl\UAVDelegate class:

  • Notice the @AutoDelegateImplementation annotation. This does the same thing here as it does in the interface, so you can remove it from either the class or the interface if you want, but it does not hurt to leave it in both.
  • Notice the @DefaultDelegate annotation. This informs Behavior Execution Engine which class to use as the default implementation of the SysML block specified by a @DelegateFor annotation.
    • A @DefaultDelegate annotation is required when multiple classes derive from the same class or interface that uses a @DelegateFor annotation. Only one @DefaultDelegate annotation may be used in that hierarchy.
    • If you have multiple SysML instance specifications that need to be implemented by different Java classes, then you need to use the MoxieJavaDelegate stereotype to specify which class to use for each instance specification.
  • Notice the BasicProperty and ListProperty Java fields for each of the UAV's SysML properties. These support change tracking of the SysML property values during the simulation.
  • Notice the @InjectByName("timeProvider") annotation in the constructor parameters. This instructs Behavior Execution Engine to inject the TimeProvider dependency from the analysis tool controller into the constructor so that it can be used within the delegate.
  • Notice the @OptionalInjectBySlot annotations in the constructor parameters. These instruct Behavior Execution Engine to inject their values from the SysML instance specification slots into the constructor so that they can be used within the delegate.
    • The @InjectBySlot annotation does the same thing, but does not allow null values.

Reinstall the delegate module

  1. If you are using an IDE, run the Gradle clean and then install tasks in your IDE to clean, assemble, and reinstall the delegate module.
  2. If you are not using an IDE, open a Command Prompt (cmd) and enter cd C:\BehaviorExecutionEngine\UAVMissionDelegateModule, replacing the path to your delegate module project as necessary. Then enter gradle clean install in the Command Prompt.
  3. After the build completes, confirm that there were no errors.

Check the SysML project simulation configuration

After deploying your delegates, remember to check the SysML project. The stereotypes applied to the simulation may affect which delegates are loaded for different simulations. By default, if the MoxieDelegateModulePaths stereotype is NOT applied, the simulation will attempt to load ALL the delegates available in your Delegate Home Directory that you can find in the SysML Client Settings.

  1. In your SysML modeling tool, open the \documentation\tutorialFiles\03\DelegateModules\UAVMission.mdzip and look for the simulation instance (the one with the MoxieSimulation stereotype applied with the Ansys logo).
  2. Examine the stereotypes applied to that InstanceSpecification and look at the Tags.
  3. To load the new module, the relative path to the newly deployed delegate module as well as the STK delegate must be specified. Add the following entries to the HomeRelativePaths tag if they do not already exist: com.agi.moxie.tutorial.uavmission and com.agi.moxie.stk
  4. Remember to save the MDZIP project before reloading it in the SysML Client.

When finished, the InstanceSpecification for your simulation should look like one of these examples:

Figure B2: Delegate Module Path Configuration

Running Diagnostics for Delegate Modules

Behavior Execution Engine provides a delegate availability report that lists all the delegates that are currently installed and available to the simulation and the SysML blocks that they correspond to. This list includes the delegates that are part of Behavior Execution Engine itself.

  1. To test the behavior of various configurations, load the \documentation\tutorialFiles\03\DelegateCodeGeneration\UAVMission.mdzip, which includes three different examples as shown in Figure B2 above.
  2. In the SysML Client, select Diagnostics > Delegate Availability Report.
  3. Look at the different simulations and note whether the UAVMissionDelegateProvider is included or not.
  4. On the simulationWithCustomDelegate selected, notice the list of delegate classes includes the Java interface and class for each of the SysML blocks in your project.
  5. Lastly, go to the Simulation tab and select the simulationWithMissingDelegate. Notice how running that simulation produces an error indicating that the delegate modules failed to load because the com.acme.failed.to.deploy.uavmission was missing.

If there is a spelling error, an incorrect path, a missing file, or otherwise an incorrect value in the stereotype, the simulation will fail by default unless you adjust the Settings to allow simulations to proceed with missing delegate modules. Generally, cases where you want to proceed by ignoring delegate module loading errors are rare. However, during delegate code development, you may want to observe the differences between the default Auto-Implementation and the effects of your new modules. To get this, we recommend you use an approach shown in Figure B2 and create different simulations with different configurations rather than ignoring errors that are likely to produce more obscure errors later during execution.

Similarly, this approach of creating different simulations for different purposes can help in cases where there are different sets of instances you want to participate or different versions of delegates that you want to try in quick succession during development. So, while this tutorial will proceed with a single simulation, feel free to create as many as is useful to you and name them appropriately.

Next Section >