Coding your Java agent logic

You override parent class methods to define a Java™ agent that meets your needs.

About this task

The Java Agent Project wizard creates a .java class, and a MANIFEST.MF file that locates the Java interfaces of your model. The .java file is a template class that extends the public EntityAgent class, and has an empty process method that you must override to handle an event type that is processed by the Java agent and exists in your model.

The EntityAgent class is an agent that is bound to an entity. You can extend ScoringEntityAgent to start a scoring service, and you can also write a Java agent that is not bound to an entity by using the base Agent class.

Tip: To use a third-party library (JAR) in your Java agent, add the JAR to the lib folder inside your Java agent project, and then add it to the Bundle-Classpath entry in the MANIFEST.MF file.

Use a combination of the following methods to complete the logic within your Java agent:

Procedure

  1. getBoundEntity() to retrieve the entity of interest, and cast the result to the interface that defines the bound entity.

    The bound entity is generated automatically from your model.

    1. If the entity does not exist, create the entity by using the createBoundEntity() method.
    For example:
    Player player = (Player) getBoundEntity();
    if (player == null) {
    player = createBoundEntity();
    } 
  2. Use the time stamp from an event or the current system time to set the date and time.
    For example, if the business definitions contained the following entry:
    a player has a last transaction time (date & time).

    You can write the following line of code:

    player.setLastTransactionTime(thisEvent.get$Timestamp());
    The value that is returned by get$Timestamp() is the time when the event is fired. get$Timestamp() is similar to the value of now used in a rule agent.

    The ZonedDateTime class is used to represent all of the time stamps in the system. If you save a time stamp in an entity, or emit an event, you must use the ZonedDateTime class to manipulate the time stamp of the event that is being processed.

  3. emit(Event event) to emit a new event to do something.

    Use getConceptFactory to programmatically construct events.

    For example:
    if (player.getBankroll() > 1000) {
       CashBonus cashBonus = getConceptFactory(ConceptFactory.class).createCashBonus(null);
       cashBonus.setAmount(100);
       emit(cashBonus);
    } 
  4. Use the Java interfaces get methods to get a value from an event or the bound entity.
    For example:
    PlayerDetails pd = playerDetailsService.getPlayerDetails(player.getPlayerId());
    Status status = Status.valueOf(pd.getAccountStatus());
    player.setStatus(status);
    1. You can also use instanceof tests to cast the event that is handled by the process method to one of the generated interfaces from your model.
  5. updateBoundEntity(Entity) to update the bound entity after it is created or modified.

    Call this method when a bound entity is modified so that entity changes are saved to the object grid. You must verify that the bound entity is successfully updated. If more than one agent is bound to an entity, the entity is passed to each agent that reads from or writes to the object grid. Therefore, if the updateBoundEntity method is not called, agents that use the entity might not receive the most current version.

    For example:
    updateBoundEntity(player);
  6. Schedule callbacks to the agent by using the schedule method.
    1. Override the process(String, String) method to handle scheduled notifications.
  7. Call getGlobalValue(String) to retrieve the value of a global event or entity aggregate.

    For more information, see Defining global aggregates.

  8. Call getJobService() to programmatically request updates to the values of global event or entity aggregates.
  9. Run geospatial calculations by calling getSpatialService() .
    You must get a geospatial service, a geometry factory from that service, and then instantiate instances of any geospatial type from that factory. All coordinates are by default in the decimal representation of world coordinates in latitude/longitude pairs, unless you define a different coordinate reference system. The following example instantiates a polygon with three points.
    @Override
    public void process(Event event) throws AgentException {
       if(event instanceof Transaction) {
          Transaction transaction = (Transaction)event;
          GeoSpatialService geometryService = GeoSpatialService.getService();
          GeometryFactory geometryFactory = geometryService.getGeometryFactory();
          Polygon poly = geometryFactory.getPolygon(
             geometryFactory.coordsToPoints(new double[][]{
                {1.0, 1.1},
                {1.2, 1.3},
                {1.4, 1.5}
             })
          );
          transaction.setPolygon(poly);
       }
    }

Results

Warning:

If a Java agent uses an excessive amount of time to complete, it can be stopped by the run time. In such cases, a CWMBD0122W message is returned. Examine the associated agent for issues that might prevent timely execution, for example, an infinite loop.

Example

There are a number of reasons why you might want to choose to create a Java agent. One example might be that you want to retrieve data from a relational database when an event arrives because the data does not exist in the grid. A Java agent can be used to initialize the data. Java is useful to map between the integers and strings in the database and the domains that are modeled for writing rules.

A solution that retrieves data from a relational database might use the following logic:

  • An OSGi service retrieves the data from a primary key. The service uses JDBC to call the relational database.
  • A Java agent subscribes to all relevant events. A process method checks whether the bound entity is null. If the entity is null, it calls the OSGi service to retrieve the data and creates the bound entity and sets properties that are based on the results from JDBC. The updateBoundEntity method is called.
  • The priority of the Java agent is set to HIGH to ensure that it runs before all other agents.
  • Rule agents that are bound to entities, which are modified by Java agents, are given a priority of LOW.
  • Rule agents know that the data is initialized from the relational data store and do not have to check for null.
Remember: When multiple agents use the same event to modify the same entity, agent priorities are used to define which agent processes the event first. For more information, see Completing the agent descriptor.