Event Notifications

Event Notifications

The Oracle Prime Projects API provides real time event notifications for changes to API objects. Event notifications enable you to design client Websocket applications that react when particular events occur in the Prime Projects API. For example, you can develop a client application that displays an informative message whenever a project object is created. Subscribe client applications to API entities using the ws://<host>:<port>/primeapi/primeevents endpoint, and use the Websocket protocol to receive Prime Projects API event notifications.

The Prime Projects API supports event notifications for actions and API entity objects.The API supports three types of object event notifications:

  • CREATE: Indicates an object has been created.
  • UPDATE: Indicates a property of an object has been modified.
  • DELETE: Indicates an object has been deleted.

The Prime Projects API supports event notification for the following objects:

  • ApiEntityProject
  • ApiEntityActivity
  • ApiEntityProjectBudget
  • ApiEntityBudgetItem
  • ApiEntityBudgetChange
  • ApiEntityBudgetTransaction
  • ApiEntityBudgetTransfer
  • ApiEnttityWorkManagerTask
  • ApiEntityWBS
  • ApiEntityResource

Websocket Client

The Prime Projects API sends event notifications using the Websocket protocol. Websocket is a TCP based communications protocol that enables client and server applications to communicate in real time. Using Websockets, the Prime Projects API can notify client applications of events when they occur. Many programming languages, such as Java, support the Websocket protocol, or provide libraries you can use to create a Websocket client. Create a client application that can receive Prime Projects API event notifications using Websockets to begin using Prime Projects API event notifications. See the Example Java Websocket Client in this document for an example of a client Websocket application.

Authentication

Prime Projects API eventing uses basic authentication to verify the permissions of websocket clients. Websocket clients must provide a valid Prime Projects username and password to connect to the Prime Projects API. Websocket requests to the ws://<host>:<port>/primeapi/primeevents endpoint must include username and password information in the form of a basic authentication header as required by other Prime Projects API endpoints.

Subscribing and Unsubscribing

To begin receiving Prime Projects API events, your Websocket client must subscribe to event notifications for particular actions or object types. To stop receiving event notifications for an action or object, you must send a subscription request with a subscription parameter value of false. To subscribe or unsubscribe to event notifications, submit a subscription request in JSON format to the ws://<host>:<port>/primeapi/primeevents endpoint. A subscription request must contain the following parameters:

  • subscription (Boolean): Indicates whether to subscribe or unsubscribe the client to notifications related to the entityObjectType. Set to true to subscribe to event notifications, set to false to unsubscribe.
  • entityObjectType (String): The API object to receive event notifications about.
  • eventTypes (List of Strings): The types of events for which notifications will be sent. Valid options are CREATE, UPDATE, and DELETE.

For example, if you want to receive event notifications for all event types for the API project object, submit a subscription request similar to the following:

{ 
      	"subscription":true, 
      	"entityObjectType":"ApiEntityProject", 
      	"eventTypes":["CREATE","UPDATE","DELETE"] 
      }

Example Java Websocket Client

The following is an example of a Java websocket client for consuming Prime Projects API event notifications:

import java.net.URI; 
      import java.nio.charset.Charset; 
      import java.util.Arrays; 
      import java.util.List; 
      import java.util.Map; 
      import java.util.Scanner; 
       
      import javax.websocket.ClientEndpointConfig; 
      import javax.websocket.CloseReason; 
      import javax.websocket.ContainerProvider; 
      import javax.websocket.Endpoint; 
      import javax.websocket.EndpointConfig; 
      import javax.websocket.MessageHandler; 
      import javax.websocket.Session; 
      import javax.websocket.WebSocketContainer; 
       
      import org.glassfish.grizzly.http.util.Base64Utils; 
       
      import com.fasterxml.jackson.core.JsonProcessingException; 
      import com.fasterxml.jackson.databind.ObjectMapper; 
       
      public class WebsocketCleint extends Endpoint { 
       
          static ObjectMapper mapper = new ObjectMapper(); 
       
          public static String getSubscriptionRequest(String option) throws JsonProcessingException { 
              switch (option) { 
                  case "project": 
                      return mapper.writeValueAsString(new SubscriptionRequest(true, "ProjectEO", Arrays.asList("CREATE", "UPDATE", "DELETE"))); 
                  case "activity": 
                      return mapper.writeValueAsString(new SubscriptionRequest(true, "ActivityEO", Arrays.asList("CREATE", "UPDATE", "DELETE"))); 
                  default: 
                      return "options"; 
              } 
          } 
       
          private static Session session = null; 
          public static String websocketEndpoint = "<host>:<port>/primeapi/primeevents"; 
          private static String userName = "<username>"; 
          private static String passWord = "<password>"; 
       
          public static void main(String[] a) { 
              try { 
                  (new WebsocketCleint()).run(); 
              } catch (JsonProcessingException e) { 
                  e.printStackTrace(); 
              } 
          } 
       
          private void run() throws JsonProcessingException { 
              String command = ""; 
              Scanner in = new Scanner(System.in); 
              while (!command.equals("exit")) { 
                  command = in.nextLine(); 
                  switch (command) { 
                      case "options": 
                          System.out.println(commands.toString()); 
                          break; 
                      case "exit": 
                          break; 
                      default: 
                          String reqJson = getSubscriptionRequest(command); 
                          if (!reqJson.equals("options")) { 
                              try { 
                                  Object json = mapper.readValue(reqJson, Object.class); 
                                  System.out.println("->Sending request to server: "); 
                                  System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(json)); 
                              } catch (Exception e) { 
                                  System.out.println("->Sending request to server: " + reqJson); 
                              } 
                              this.sendMessage(reqJson); 
                          } 
                  } 
              } 
              in.close(); 
          } 
       
          private ClientEndpointConfig getClientEndPointConfig() { 
              return ClientEndpointConfig.Builder.create().configurator(new ClientEndpointConfig.Configurator() { 
       
                  @Override 
                  public void beforeRequest(Map<String, List<String>> headers) { 
                      String auth = "Basic " + Base64Utils.encodeToString((userName + ":" + passWord).getBytes(Charset.forName("UTF-8")), false); 
                      headers.put("Authorization", Arrays.asList(new String[] { auth })); 
                      super.beforeRequest(headers); 
       
                  } 
              }).build(); 
          } 
       
          public WebsocketCleint() { 
              try { 
                  URI endpointURI = new URI("ws://" + websocketEndpoint); 
                  WebSocketContainer container = ContainerProvider.getWebSocketContainer(); 
                  container.connectToServer(this, getClientEndPointConfig(), endpointURI); 
              } catch (Exception e) { 
                  e.printStackTrace(); 
              } 
          } 
       
          @Override 
          public void onClose(Session userSession, CloseReason reason) { 
              System.out.println("closing websocket"); 
              this.session = null; 
              System.exit(0); 
          } 
       
          public void sendMessage(String message) { 
              this.session.getAsyncRemote().sendText(message); 
          } 
       
          @Override 
          public void onOpen(Session session, EndpointConfig arg1) { 
              System.out.println("Websocket session is open"); 
              this.session = session; 
              session.addMessageHandler(new MessageHandler.Whole<String>() { 
       
                  @Override 
                  public void onMessage(String text) { 
                      try { 
                          Object json = mapper.readValue(text, Object.class); 
                          System.out.println("<-Message from Prime is:"); 
                          System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(json)); 
                      } catch (Exception e) { 
                          System.out.println("<-Message from Prime is: " + text); 
                          // e.printStackTrace(); 
                      } 
       
                  } 
              }); 
              System.out.println(commands.toString()); 
          } 
       
          public static StringBuilder commands = new StringBuilder(); 
          static { 
              commands.append("Options :\n"); 
              commands.append("activity : Subscribes to ACTIVITY CREATE, UPDATE, DELETE events\n"); 
              commands.append("project : UnSubscribes to PROJECT CREATE, UPDATE, DELETE events\n"); 
              commands.append("exit : closes websocket connection"); 
          } 
      } 
       
      class SubscriptionRequest { 
       
          public Boolean subscription; 
          public String entityObjectType; 
          public List<String> eventTypes; 
       
          public SubscriptionRequest(Boolean subscription, String objectType, List<String> eventTypes) { 
              this.subscription = subscription; 
              this.entityObjectType = objectType; 
              this.eventTypes = eventTypes; 
          } 
      }

Notes:

Events are only emitted when properties stored directly on an object, an object's configured fields, or an object's code values are modified. Object fields that reference other object's properties do no emit events upon modification. For example, modifications to the projectFinancial property on a project object will not trigger an update event for the project object.

Objects deleted using cascade delete functionality will not trigger a delete event.

If a code value of an object is deleted, an update event will be emitted, and the deleted code value will not appear in the object's updated properties.

If multiple object codes or flex fields are updated in a single request, each modified code value and flex field will trigger an update event for the object.

If you create an object containing code and flex fields, only the object's create event will be triggered. An update event for code and flex properties will not be triggered on object creation.

If an object property containing a referenced value is deleted, the object's update event will trigger, and the deleted property value will not be included in the object's updated properties. For example, deleting the projectFinancial property on a project object will trigger an update event for the project object.

If an object's create, update, or delete operations impact other objects within the Prime Projects instance, you will receive a notification for the target object and all objects impacted by the operation.