Annotations

Moxie uses annotations in order to understand how to process your delegate code. Learning to use them effectively can help make writing your delegates easier. You should pay especially close attention to how you use the @DelegateFor and @DefaultDelegate annotations. Assuming that all of the @DelegateFor annotations in the following list are for a single block:

  • If you do not annotate any delegates with @DelegateFor, then Moxie will auto-implement a delegate for the block at runtime.

    This case does not require you to use any annotations, but in the following cases, you can annotate delegates with @AutoDelegateImplementation to have Moxie auto-implement parts of the delegates that are missing.

  • If you annotate exactly one delegate with @DelegateFor, then Moxie will use that delegate for the block.
  • If you annotate more than one delegate with @DelegateFor, then Moxie will throw an error at runtime unless you also do one of the following:
    • Annotate exactly one of the delegates with @DefaultDelegate, in which case Moxie will use that delegate for the block.
    • Apply MoxieJavaDelegate stereotypes to every instance specification of the block, in which case Moxie will use the delegates specified in each stereotype for their respective instance specifications of the block.

      The MoxieJavaDelegate stereotype overrides all of the other cases in this list, but it only applies to its instance specification, not any other instance specifications of the same block.

  • If you annotate a delegate interface or abstract class with @DelegateFor, then Moxie will only use that delegate if you also annotate it with @AutoDelegateImplementation.
  • If you annotate a delegate with @DelegateFor and other delegates inherit from that first delegate, then Moxie will treat both the first delegate and the inheriting delegates as if they were all annotated with @DelegateFor, resolving them according to the previous bullets.

If you use an inheritance hierarchy for your delegates, then you should be careful to specify the base delegate that represents the block in any contexts that need to be able to accept any of the inheriting delegates. For example, if you have an interface that represents the block and you have concrete classes that implement that interface, then in a method that needs to accept an instance of the block you should use the interface as the parameter type.

Annotation Description
@DelegateFor("Structure::Qualified::Name")

Maps a SysML block to its corresponding Java delegate. AGI recommends that you define one unique interface with a @DelegateFor annotation and then provide different concrete implementations as desired. While an interface is not required, it can be useful for maintaining the delegate implementations in cases where the SysML structure may change over time. That way, updating the interfaces (for instance by using the Code Generator) will provide a way for the compiler to help update code to be consistent with the SysML.

You can use the Moxie-Base::Configuration::MoxieJavaDelegate stereotype to reference any concrete class derived from a class or interface annotated with @DelegateFor. You can then have two or more concrete implementations for a given SysML type, and by applying this stereotype to individual SysML instances, you can specify which Java implementation to use with each instance.

If more than one delegate references the same qualified name in its @DelegateFor annotation, an exception will be thrown at simulation runtime.

@DelegateFor("Structure::Passenger")
public interface Passenger extends SpatialEntity { ... }

@DefaultDelegate

If two or more classes derive from a base class or interface annotated with @DelegateFor, the @DefaultDelegate annotation informs the Moxie Engine which one should be used in the simulation. To override the specified @DefaultDelegate without having to recompile your code, apply the Moxie-Base::Configuration::MoxieJavaDelegate stereotype to that SysML instance. Similarly to @DelegateFor, only one @DefaultDelegate may be present for any Java class which derives from a @DelegateFor base class or interface. If there are zero concrete classes specified with the @DefaultDelegate annotation and the SysML instance has no MoxieJavaDelegate stereotype applied, Moxie will first attempt to find an abstract class or interface to use. If this fails, it will attempt to provide an implementation for the element automatically using default behaviors.

In the following snippet, both AdultPassenger and ChildPassenger implement Passenger, which is annotated with @DelegateFor("Structure::Passenger"). In this case, AdultPassenger will be used, since it is annotated with @DefaultDelegate.

@DefaultDelegate
public class AdultPassenger implements Passenger { ... }
public class ChildPassenger implements Passenger { ... }

@AutoDelegateImplementation

This annotation is optional.

By annotating a class or interface with @AutoDelegateImplementation, it indicates to the Moxie Engine that it should provide a default implementation automatically for any properties or operations that haven't been implemented explicitly. You can find more details in the Auto Implementation topic.

In the following snippet, the @AutoDelegateImplementation annotation will inform the Moxie Engine to implement any properties or operations that exist in the Passenger block but are not implemented in the Java delegate.

@AutoDelegateImplementation
@DefaultDelegate
public class AdultPassenger implements Passenger { ... }

@EnumerationLiteralName

This annotation is optional.

This annotation enables you to map enumeration literals in your model to Java enum constants. In particular, if there is a difference in spelling or formatting between a model enumeration literal and its Java counterpart, this annotation will address that for you. If no such annotation is specified, Moxie attempts to map to a literal with the same spelling and formatting on both sides.

In the following snippet, the enumeration literals for the model do not match their Java enum constant counterparts.

@DelegateFor("Structure::BalloonStatus")
public enum SampleBalloonStatus {
    @EnumerationLiteralName("Grounded")
    WAITING,
    @EnumerationLiteralName("Loading")
    LOADING,
    @EnumerationLiteralName("InFlight")
    IN_FLIGHT,
    @EnumerationLiteralName("Unloading")
    UNLOADING
}

Constructors

Annotation Description
@InjectByName("injectedDependencyName")

Annotates an injection constructor parameter and retrieves the dependency by name. The dependencies for existing tools are listed with their corresponding AnalysisToolController. You can provide custom dependencies to delegates by extending your own AnalysisToolController.

public SampleBalloonOperator(
        @InjectByName("stateMachineRemoteControl") StateMachineRemoteControl stateMachineRemoteControl,
        @InjectByName("timeProvider") TimeProvider timeProvider,
        @InjectBySlot("balloon") Balloon balloon,
        @InjectBySlot("passenger") Passenger passenger,
        @InjectBySlot("launchPadAltitude") FixedScalarValue launchPadAltitude,
        @InjectBySlot("targetAltitude") FixedScalarValue targetAltitude,
        @InjectBySlot("maxFlightDuration") DefaultFixedDuration maxFlightDuration) { ... }

@InjectBySlot("propertyName")

Annotates an injection constructor parameter and provides the value found in the slot for the corresponding property of the Instance Specification.

If this annotation is specified but a slot value is not provided in the instance specification, a NoSuchElementException is thrown at the start of the simulation.

If a slot value is provided in the instance specification, then the system will perform a wire-up to set the value whether or not this parameter is present in the constructor. This simply provides a useful way to gain access to the value at construction time. The type of the parameter must match its Java equivalent as specified by the @DelegateFor annotation. In order to circumvent circular dependencies between instances, you may instead specify the type of the parameter as javax.inject.Provider<T> (for example, Provider<OtherDelegateType>). See the wire-up section of Properties and Operations for more details on how the system handles initializing values.

@OptionalInjectBySlot("propertyName") This annotation behaves similarly to @InjectBySlot except that missing slot values result in null values being injected to the constructor rather than an exception being thrown.
@InjectStereotype CustomStereotypeImplementation

The InjectStereotype annotation enables you to accept an instance of any custom stereotype applied to the delegate instance in SysML. The only stipulation is that the Java class CustomStereotypeImplementation is registered with the Delegate Provider. If no such stereotype is applied, the parameter value will be null.

Stereotypes

MoxieJavaDelegate

The Moxie-Base::Configuration::MoxieJavaDelegate stereotype allows you to map Instance Specifications explicitly to their corresponding delegate implementations. This is required when multiple implementations exist for the same block and either (a) none of the implementations have been annotated with @DefaultDelegate or (b) you wish to override the type designated as the @DefaultDelegate with a different type.

Figure 1 shows this stereotype applied to an instance named passenger. ChildPassenger is specified as the type to be used for the Passenger block. This informs the Moxie Engine that ChildPassenger will now be used at simulation runtime instead of AdultPassenger, even though AdultPassenger is annotated with @DefaultDelegate. This is especially useful for testing different implementations, as it allows you to switch between them without having to recompile your Java first.

Figure 1: Configuration stereotypes for a delegate that uses STK

MoxieStkExistingObject

If you are using STK as your analysis tool, you can take advantage of the Moxie-STK::Configuration::MoxieStkExistingObject stereotype to map STK Scenario objects to their corresponding Instance Specifications. Figure 1 demonstrates this.

In Figure 1, the stkObjectPath stereotype tag informs Moxie which STK object an Instance Specification corresponds to. This is useful in cases where there is a pre-built STK scenario that forms the basis of the simulation. This can include pre-configured background objects that may or may not have specific behaviors defined in SysML but are included as dependencies for objects that are involved in executing the behaviors.