Application Packaging Standard

Last updated 18-Mar-2019

Business API

This document introduces the high level business API (Biz API) in the aps.biz name space that substantially simplifies the interaction of an APS application with the business modules of the platform.

Business module Module actions Application actions
User management Operations with service users Assign and configure services for users
Domain management Operations with DNS zones Not implemented yet
Subscription management Operations with resource limits and usage Change resource limitation and usage

Resource Management

The following sections consider two typical resource management models. In both scenarios, there is an application that assigns its service as amount of resources to users.

The management platform controls the following objects and processes:

  • A service plan contains a resource rate (RR) bound with the considered application resource (service) that allows a provider to sell or upsell up to Max amount of the resource.
  • A subscription based on the service plan includes the purchased resource with a total Limit not higher than Max.
  • A subscriber (customer) can assign the resource to service users. The total assigned amount cannot exceed the Limit set in the subscription.

The following resource management models differ in resource usage control.

Storage Management

In this case, the platform determines the actual resource usage by means of a resource counter that the platform polls periodically. Generally, the resource usage is less than the assigned amount. The business model implies a customer pays for the actual resource usage following the pay-as-you-go method. However, the application takes into account the total assigned amount and compares the subscription Limit with the Assigned total when assigning the service to users.

../../../../_images/storage.png

License Management

In this scenario, once the subscriber assigns a license for a service to a service user, the platform considers one more unit of the resource is used. In this case, the resource usage equals the assigned amount.

../../../../_images/license.png

Biz API Workflow

To monitor and change resource usage and assignment on high level, the Biz API exposes a few methods with the following typical workflow in a UI view:

../../../../_images/flow.png
  1. To present a resource usage data, a view sends a high level getResourcesInfo request. The response must contain the resource usage data that the view will draw on the screen.
  2. The application can enable or disable some actions (buttons) in dependence of the availability of the respective resources the customer is subscribed to. To make decision, the view sends a canChangeUsage request to ensure if a certain action can be completed.
  3. When a customer changes a resource configuration or assigns resources to users, the view sends a requestUsageChange request for changing resource usage.
  4. Finally, a view will request to commit the requestUsageChange request sent earlier by calling the commit method.

Meta Definition

A view that uses the aps.biz methods must provide the predefined view-plugin placeholder in the application APP-META.xml file:

<plugin-placeholder id=“http://www.aps-standard.org/core/package#biz" />

The APS JS module responsible for the aps.biz methods will plug into the specified placeholder.

API Methods

To support async operations, each of the aps.biz methods returns a dojo/Deferred promise for the output specified in the table below.

Method Input Output Description
getResourcesToBind -
{
users: [users],
domains: [domains],
subscriptions: [subscriptions]
}
Returns up to three lists of objects to bind the application services to. Currently, the method is integrated with the user creation wizard that returns the users list.
getResourcesInfo
{ filter: [<resource filters>] }
A resource filter:
{
apsType: <APS type>,
apsProperty: <counter property>,
apsId: <APS ID of a reference resource>
}
[resources]
Each entry is a resource representation
Returns a list of entries, each containing billing data about a requested resource. Primary keys for filtering resources are apsType, apsProperty, and apsId.
canChangeUsage
{deltas:[resource requests]}
A resource request:
{
apsType: <APS type>,
apsProperty: <counter property>,
apsId: <APS ID of a reference resource>
delta: <request for increase>
}
- true - update allowed
- false - update not allowed
Requests if the subscription allows assigning the specified amounts (deltas) of resources. For example, an application can enable or disable a button on the result of the method call.
requestUsageChange
{
deltas: [resource requests],
operations: [operations]
}
Deferred object. In the case of success, it returns the input object with additional limit and rateId fields. Otherwise, it rejects the request. Requests the platform for the specified amounts (deltas) of resources. If the subscription limitation does not prevent it, the platform processes the required operations to assign the requested resources. Otherwise, it will propose the customer to increase the subscription limits by purchasing additional resources. The commit method is necessary to commit the requested changes.
requestLimitsChange
{
limits: [new limits]},
operations: [operations]
}
Deferred object. In the case of success, it returns the input object with additional limit and rateId fields. Otherwise, it rejects the request. Requests the platform to update resource limits. Each element of the limits array is an object consisting of the resource apsType, apsProperty (for counters), apsId (for references), and new limit. The commit method is necessary to commit the requested changes.
commit -
- Promise resolved - success
- Promise rejected - failure
Commits the changes requested by requestUsageChange and requestLimitsChange methods. If a view is plugged into a wizard the latter must use this method. Otherwise, the application view must call this method itself.

Note

1. If there were more than one aps.biz.requestUsageChange requests for changing the same resource in a subscription before the aps.biz.commit method is called, the system will commit only the last request.

  1. In a wizard, it is not allowed to use the aps.biz.requestLimitsChange requests.

getResourcesToBind

Currently, an application view plugged into the system user creation wizard can use this method to get a list of new users whom the application service must be assigned to.

The method returns an object in the form of:

{ users: [<user-1>, <user-2>,...] }

Each <user> in the list is a JSON representation of a new user in the format as in the following example:

{ "aps": {
   "type":"http://parallels.com/aps/types/pa/service-user/1.2",
   "id":"6bbc5494-f525-5475-c61e-de8aaf1edfd3"},
   "addressPostal":{},
   "locale":"en_US",
   "givenName":"Andy",
   "familyName":"Williams",
   "email":"aw@aps.test",
   "displayName":"Andy Williams",
   "fullName":"Andy Williams",
   "login":"aw@aps.test",
   "isAccountAdmin":false
}

The following example demonstrates this method:

aps.biz.getResourcesToBind().then(function(resources) {
   var users = resources.users;
   // ... Assign a service to users
});

getResourcesInfo

An application can request the platform for the list of resources in a subscription. Each returned resource representation contains commercial properties, such as name, limit, usage, and so on.

  • Input - a named list containing filter as an array of filters and optionally subscriptonid
  • Output - a dojo/Deferred promise for a list of requested resources

The getResourcesInfo method call looks as follows:

getResourcesInfo({ filter: [<filter-1>, <filter-2>,...] },
   subscriptionId: <subscription APS ID>
);

If the subscriptionId input is missing, the method uses by default the aps.context.subscriptionId value.

Each filter contains a named list of up to three parameters (all are optional) to filter resources:

{
   apsType: "<APS type ID>",
   apsProperty: "<property of the Application Counter resources>",
   apsId: "<APS ID of the Application Service Reference resources>"
}

The method returns an array of resources:

[<resource-1>, <resource-2>,...]

Each resource representation complies with the following schema:

{
   "apsType":     { "required": false, "type": "string" },
   "apsProperty": { "required": false, "type": "string" },
   "apsId":       { "required": false, "type": "string" },
   "name":        { "required": false, "type": "string" },
   "min":         { "type": "integer" },
   "usage":       { "type": "integer" },
   "limit":       { "required": false, "type": "integer" },
   "max":         { "type": "integer" },
   "unit":        { "required": false, "type": "enum" },
   "priceText":   { "required": false, "type": "string" },
   "isLimited":   { "type": "boolean"},      // Added by BSS
   "isUpsellPossible": {"type": "boolean"}   // Added by BSS
}
Property Type Notes
apsType URI APS type ID as specified in APS Type ID
apsId GUID Unique resource ID as specified in Resources
apsProperty String
Only Application Counter resource types contain this property that is the name of a Counter structure as specified by the core Resource APS type.
The string pattern is ^[a-zA-Z_][a-zA-Z0-9_]*$.
name String Can be localized.
description String Can be localized.
min
0
Positive integer
Specified by the respective resource rate.
max
0
Positive integer
undefined
Specified by the respective resource rate.
usage
0
Positive integer
Current resource usage.
limit
0
Positive integer
Specified by the respective subscription.
unit String Can be localized.
priceText String Can be localized.
isUpsellPossible Boolean It is possible to upsell the resource in accordance with the respective resource rate. The field is added by BSS.
isLimited Boolean The resource amount is limited as specified in the subscription. The field is added by BSS.

Note

  1. Only resources of the Application Service Reference class contain apsId.
  2. Only resources of the Application Counter classes contain apsProperty.

3. priceText is returned by the billing system. It contains the price per a subscription period, for example ‘$4/month for 1 Additional VPS’.

  1. In the processing code, read the limit property only if isLimited==true.

The method filters the subscription resources using the best-match in the following order:

  1. apsType, apsProperty
  2. apsType, apsId
  3. apsType

The following sample call must return the resource of the specified vps type and the diskspace counter specified by the context type:

aps.biz.getResourcesInfo({ filter: [{
      apsType: "http://aps-demo.org/samples/basic/vps"
   }, {
      apsType: "http://aps-demo.org/samples/basic/context",
      apsProperty: "diskspace"
}]}).then(function(resources) {
   //... process the returned array
});

canChangeUsage

An application can evaluate whether the current customer is able to request the specified amount of resources.

  • Input - a named list containing the deltas array of requests for change
  • Output - a dojo/Deferred promise for the true or false response

For the current subscription, the input is an object in the following format:

{ deltas: [<request-1>, <request-2>,...] }

An AWS application can specify several subscriptions in the method call in the form of:

{
   <subscriptionId-1>: { deltas: [requests] },
   <subscriptionId-2>: { deltas: [requests] },
   ...
}

In this case, the method will return a response mapped to subscription IDs, for example:

{
   <subscriptionId-1>: true,
   <subscriptionId-2>: false,
   ...
}

Each request is an object complied with the following schema containing the filtering parameters and the requested total resource amount:

{
   "apsType":     { "required": false, "type": "string" },
   "apsProperty": { "required": false, "type": "string" },
   "apsId":       { "required": false, "type": "string" },
   "delta":       { "type": "integer" }
}

The delta property is the amount of the specified resource to assign.

The following example tests if the current subscription allows assigning 2 more VPSes and 50 GB of disk space:

aps.biz.canChangeUsage({deltas: [{
      apsType: "http://aps-demo.org/samples/basic/vps",
      delta: 2
   }, {
      apsType: "http://aps-demo.org/samples/basic/context",
      apsProperty: "diskspace",
      delta: 50
}]}).then(function() {...});

requestUsageChange

An application calls this method to request assignment of the specified resources and to request a set of operations over those resources.

  • Input - a named list containing the deltas array of requests for change and the operations array of requested operations
  • Output - a dojo/Deferred promise

In the case of success, the method returns the input object with the following additional fields:

  • limit - the updated limit of the resource
  • rateId- the internal ID of the updated resource in the platform

For a single subscription, the input is an object in the following format:

{
   deltas: [<request-1>, <request-2>,...],
   operations: [<operation-1>, <operation-2>,...]
}

An AWS application can specify several subscriptions in the method call in the form of:

{
   <subscriptionId-1>: {
      deltas: [<requests>],
      operations: [<operations>]
   },
   <subscriptionId-2>: {
      deltas: [<requests>],
      operations: [<operations>]
   },
   ...
}

The deltas array and the requests inside it are of the same format as in the canChangeUsage method. Each request is an object complied with the following schema:

{
   "apsType":     { "required": false, "type": "string" },
   "apsProperty": { "required": false, "type": "string" },
   "apsId":       { "required": false, "type": "string" },
   "delta":       { "type": "integer" }
}

Normally, an application calls the specified operations to implement the requested deltas, although formally the former are not related to the latter. The operations are called one-by-one in the specified sequence. An operation can be one of the following:

  • provision - create a specified resource

    { "provision": { resource JSON representation } }
    
  • unprovision - remove a specified resource

    { "unprovision": { apsId: "<resource APS ID>" } }
    
  • call - a custom operation with the following properties:

    • resourceId - APS ID of the resource to process
    • operation - the operation name as declared in the resource schema (APS type)
    • parameters - named list of parameters to pass to the method as input arguments

    Note

    Currently, it works with custom operations declared in accordance with the following rules:

    • The verb property must be “POST”.
    • The operation name must equal its path property.
    • The operation expects only one parameter whose kind property is “body”.

The following example illustrates how to use the method to request totally for 1 more VPS and 50 GB of additional disk space. If the subscription allows assignment of the requested resources, the unprovision operation removes an old VPS and then the provision operations create two more VPSes:

aps.biz.requestUsageChange({
   deltas: [{
         apsType: "http://aps-demo.org/samples/basic/vps",
         delta: 1    // Totally, one more VPS is needed
      }, {
         apsType: "http://aps-demo.org/samples/basic/vps",
         apsProperty: "diskspace", // Counter
         delta: 50  // Assign 50 GB of disk space
   }],
   operations: [
      { unprovision: {apsId: oldVpsId} },           // Remove an old VPS
      { provision: getPlainValue(self.model.newVPS[1]) } // Create a VPS
      { provision: getPlainValue(self.model.newVPS[2]) } // One more VPS
   ]
})

requestLimitsChange

An application uses this method to update the resource limitation in a subscription or in a set of subscriptions.

  • Input - a named list containing the limits array of requests for change and the operations array of requested operations
  • Output - a dojo/Deferred promise

In the case of success, the method returns the input object with the following additional fields:

  • limit - the updated limit of the resource
  • rateId- the internal ID of the updated resource in the platform

For a single subscription, the input is an object in the following format:

{
   limits: [<request-1>, <request-2>,...],
   operations: [<operation-1>, <operation-2>,...]
}

Normally, to apply the requested limits, the application requests some operations to be called one-by-one in the specified sequence.

An AWS application can request updates in several subscriptions in the form of:

{
   <subscriptionId-1>: {
      limits: [<requests>],
      operations: [<operations>]
   },
   <subscriptionId-2>: {
      limits: [<requests>],
      operations: [<operations>]
   },
   ...
}

Each request in the limits array is an object complied with the following schema:

{
   "apsType":     { "required": false, "type": "string" },
   "apsProperty": { "required": false, "type": "string" },
   "apsId":       { "required": false, "type": "string" },
   "limit":       { "type": "integer" }
}

The limit on the subscribed resource matching the filtering parameters will be updated to the specified limit value.

The following example defines a function that updates a resource limit:

updateBuyAmount: function(newValue) {
   if (isNaN(newValue) return;
   return aps.biz.requestLimitsChange({
       limits: [{
           apsId: this.owcProfile.apsId,
           limit: newValue + this.owcProfile.limit
       }]
   })
   .then(null, displayError);
}

commit

The method is necessary to commit the requests and operations specified by the requestUsageChange and requestLimitsChange methods. It does not require any input arguments.

The following example illustrates a sequence of method calls:

  1. Call the aps.biz.requestLimitsChange method to determine if update of the specified limits is allowed.
  2. After the previous request is resolved, call the aps.biz.commit method to commit the request.
  3. If the commit was successful, call the submit navigation method.
aps.biz.requestLimitsChange({
   limits: [{
      apsId: profile.aps.id,
      limit: amount
   }]
}).then(function() {
   return aps.biz.commit();
}).then(function() {
   this.submit();
},
displayError
);

Composite Resources

Terminology

When the platform contains both parts, the Operations Support System (OSS) and Business Support System (BSS), the Biz API allows operating resources only if those resources are presented in the respective service plan. A resource rate sets the lower limit, upper limit, and the included amount of the respective resource. In addition to the included amount of a resource, a customer can buy more amount of that resource. The Prepare Product Deployment Configuration and Deploy Product steps of the User Management demo illustrate configuration of resource rates.

In BSS, the provider can add a resource to one or more composite resources and then create resource rates in a service plan for those composite resources. A composite resource is a bunch of ordinary resources with respective rates. For example, the provider wants to sell mailboxes along with disk space for those mailboxes. In this case, it is possible to create several composite resources with different number of mailboxes and amount of disk space in each. A customer is able to update the limits in their subscription by purchasing one or any combination of composite resources presented by the respective resource rates in the service plan. The Customize Resource Rates (optional step) step of the User Management demo illustrates configuration of composite resources and the respective resource rates.

Biz API Processing

When an application view sends an aps.biz.requestUsageChange or aps.biz.requestLimtsChange request to increase resource usage and to perform some provisioning operations, the platform validates if the specified subscription allows that usage. If the current limits in the subscription do not allow the request, the user panel notifies the customer about the upsell options.

For example, if the request exceeds the limit on mailboxes, the customer is able to select one of composite resources containing the mailbox resource.

The process looks as follows:

  1. Inside the onContext method, the aps.biz.requestUsageChange method requests the platform if it is able to increase the resource usage and perform the required provisioning operations in scope of a certain subscription.

    Note

    It is important to call the aps.biz.requestUsageChange method inside the onContext method. In this case, the user panel will notify the customer about the upsell options. The customer will be able to cancel the operation, or select another amount of the resource, or select the proper upsell option. After that, the application will be able to call the aps.biz.requestUsageChange method again with the updated request.

    The New Users view code of the User Management demo illustrates the use of Biz APi.

  2. The platform identifies that the request leads to exceeding the current resource limit in the specified subscription.

  3. The platform figures out all resource rates that can increase the resource limit and prompts the customer to select and buy one of the options.

    The Add Users provisioning step of the User Management demo illustrates how it looks like in user panel.

  4. The customer selects one of the options to buy and clicks the Submit (in a final view of a wizard or in a standalone view) or Next (in an intermediate view of a wizard). The respective handler calls the aps.biz.commit method to commit the aps.biz.requestUsageChange request.

  5. UX1 presents an order to purchase the selected option and the customer confirms the purchase.

  6. The platform processes the order payment and completes the provisions operations required by the aps.biz.requestUsageChange method.

Limitations

  1. The link, unlink, and unprovision operations are not supported.
  2. The requestLimitsChange method does not function in wizards.
  3. It is not allowed to request changes for the same resource from more than one view in the same wizard or concurrently. Breaking this limit leads to unpredictable consequences.
  4. If Biz API methods are applied to a resource, ensure the respective service plan in BSS contains a resource rate for that resource. You do not need to care of it when testing your application on a lab system without BSS.

Examples

Collect Subscription Resources

This example illustrates how to collect commercial data about subscription resources in a model and then to sync the latter with widgets.

  1. Declare a model containing resources filtered by various parameters. You can sync the model with widgets to visualize its contents:

    var model = getStateful({
       vpsOffers: {},
       cpuCores: {},
       memory: {}
    });
    
  2. Request for resources in the current subscription filtering them by various parameters and save the returned results in the model:

    aps.biz.getResourcesInfo({filter: [{
             apsType: "http://aps-standard.org/samples/suwizard1p/offer/1.0"
          }, {
             apsType: "http://aps-standard.org/samples/suwizard1p/context/1.0",
             apsProperty: "cpuusagetotal"
          }, {
             apsType: "http://aps-standard.org/samples/suwizard1p/context/1.0",
             apsProperty: "ramusagetotal"
       }]
    }).then(function(data) {
          model.set("vpsOffers", data.reduce(function(offers, item) {
             if (item.apsType === 'http://aps-standard.org/samples/suwizard1p/offer/1.0') {
                offers[item.apsId] = item;
             }
             return offers;
          }, {}));
          model.set("cpuCores", data.find(function(item) {
             return item.apsProperty === 'cpuusagetotal';
          }));
          model.set("memory", data.find(function(item) {
             return item.apsProperty === 'ramusagetotal';
          })));
    });
    

Test Available Resources

The example verifies if a subscription allows assignment of the specified amount of resources.

  1. Declare a model representing availability of resources for upgrade. You can sync the model with widgets to visualize its contents, for example to enable or disable some buttons.

    var model = getStateful({
       canChangeVPS: "",
       canChangeOffer: ""
    });
    
  2. Test the possibility to assign resources filtered by various parameters and collect the returned results in the model:

    var subscriptionId = aps.context.vars.context.aps.subscription;
    
    aps.biz.canChangeUsage({
       deltas: [{
          apsType: "http://aps-standard.org/samples/suwizard1p/vps/1.0",
          delta: 3
       }]
    }).then(function(result) {
       model.set("canChangeVPS", result);
    }, function() {
       console.error("canChangeUsage by APS type failed");
    });
    
    aps.biz.canChangeUsage({
       deltas: [{
          apsId: "78b5e708-5f8a-431b-ba42-9eb63fa09f2e",
          delta: 3
       }]
    }).then(function(result) {
       model.set("canChangeOffer", result);
    }, function() {
       console.error("canChangeUsage by APS ID failed");
    });
    

Assign Service to Users

The example is typical for a view plugged into the user creation wizard. It gets a list of new users calling the getResourcesToBind method and requests the application service assignment to each user by calling the requestUsageChange method. If the request succeeds the view forwards the customer to the next step of the wizard. Finally, the wizard must commit all aps.biz requests for change.

aps.biz.getResourcesToBind().then(function(resources) {
     var users = resources.users;
     return aps.biz.requestUsageChange({
          deltas: [{
               apsType: "http://aps-standard.org/samples/suwizard1p/vps/1.0",
               delta: users.length
          }],
          operations: users.map(function(user) {
               return {
                    provision: lang.mixin(getPlainValue(self.model.data), {
                         user: user,
                         userName: user.fullName
                    })
               };
          }),
          subscriptionId: aps.context.vars.context.aps.subscription
     });
}).then(function() {
     aps.apsc.next();
});

Remove Resources

The example illustrates how to use the unprovision operation in the requestUsageChange method to remove the selected services (VPSes) in the following order:

  1. Collect all selected VPSes in the sel array.
  2. Create the request object containing deltas as the number of the selected VPSes and the list of unprovision operations.
  3. Request the aps.biz module for the change by calling the requestUsageChange method.
  4. Call the commit method to start the requested removal of the VPSes.
  5. If the last operation succeeded, refresh the grid. Otherwise pop-up the error message.
/* The onClick handler for the "Delete" button - "this" object */
var remove = function() {
   /* Get confirmation from the user for the delete operation */
   if (!confirm("Are you sure you want to delete VPSes?")) {
      this.cancel(); // Release the "Delete" button
      return;
   }
   var sel = grid.get("selectionArray"); // All VPSes selected for removal

   /* Clear the current messages on the screen */
   page.get("messageList").removeAll();

   var data = {
      deltas: [{
         apsType: "http://aps-standard.org/samples/suwizard1p/vps/1.0",
         delta: -sel.length   // Decreasing the resource amount
      }],
      operations: sel.map(function(vpsId) {
         return {unprovision: {aps: {id: vpsId}}}; // An operation for each VPS
      })
   };
   aps.biz.requestUsageChange(data).then(function() {
         return aps.biz.commit();
   }).then(function() {
         grid.refresh();
      }, function() {
         aps.apsc.displayMessage("Resources can't be deleted");
   }).always(function() {
         this.cancel();
         sel.set("length", 0);   // Make the selected array empty
   }.bind(this));
};