This is documentation for Apprenda 7 and 8.
Documentation for newer version is available at https://new.docs.apprenda.com.

Features

Proceed straight to specific information about:

Features Overview

In Apprenda, Features represent items that will become available to a User if allowed by their subscription. In addition to representing general availability, they can also denote that usage of the Feature may be restricted somehow depending on the User's subscription. Features are relevant only to applications deployed with Authorization or Multi-tenancy.

Typically, Features are determined when eliciting requirements for an application. It is important to understand that Features represent only discreet actions that can be taken and the type of restriction that may apply. Any permissions or  quantities involved to conduct the action and other restriction terms are defined when configuring User- or account-level subscription plans in the application's Entitlement Definition in Apprenda. 

Choosing the Correct Feature Type
The table below lists the Feature types available in Apprenda along with a description and examples.

Feature Type Description Examples
Toggle These Features are those that are considered “on” if a User is subscribed to use the Feature or “off” if they are not. This is the simplest Feature type in Apprenda, because no other usage restriction can be defined. 
  • Generate reports in a CRM application
  • Create custom fields in a project management application
Boundary These Features require that some upper or lower boundary be adhered to during execution. Their value will be calculated by the application at runtime and checked against the value defined by the User's subscription. 
  • Limit upload size
  • Limit dollar amount of a project budget
Limiter Some applications require the ability to track a rolling count that can be compared to some upper maximum. If the rolling count is less than the upper maximum, a certain action is allowed. If the maximum is reached, the action is blocked. 
  • Number of projects open in a project management application
  • Number of custom fields that can be configured
Block

Block Features are constrained to a certain quantity during the subscription cycle. Apprenda will track usage of the Feature, and when the block amount has been exhausted the action is blocked. The block is replenished at the beginning of the next subscription cycle.

  • Text messages sent in subscription cycle
  • Unique reports that can be generated over time

Once the list of Features has been created, you must then include them with the application's Definition; the best practice for doing so is to list them in a Deployment Manifest included with your application archive. Once they are defined, you can use Apprenda's API to:

  • Quickly determine if the logged-in User has access to the Feature, and, if so, check its current limit, block size, or boundary if applicable. This is useful for disabling something in the user interface or otherwise changing how the user interface is displayed to the User. 
  • Tell Apprenda that the User has accessed a Block or Limiter Feature and to update its internal meter. The meter tracks the usage of the Feature for the User or Tenant. 

Working with Features in the .NET Guest App API

Features are available only if they exist on the User’s subscription for the current application serving the request. Actions pertaining to Feature checking and usage can be done either via attributes applied to WCF operation contracts or by accessing the API directly.

If you use attributes applied to WCF operation contracts, be aware that the functions only apply to inbound service calls, and not on calls coming from other service methods within the same instance. Use the attributes only in situations where an application does not expect code internal to the current instance to be making calls to the signed service method.

Toggle Features either grant or deny access to code wrapped in an Apprenda API call. There are no complex dynamics associated with toggles.

C# Example – Toggle Features

//Using a feature for service level feature control	
[OperationContract]
[ToggleFeature("Generate Reports")]
public Report BuildReport(DateTime startDate, DateTime endDate, Guid templateId)
{		
	IReportTemplate template = TemplateRepository.Instance.Get(templateId);
	return template.Generate(startDate, endDate);		
}

//A direct API call in situations needing fine control
[OperationContract]

public Dashboard GetDashboard()
{		
	Dashboard configuredDashboard = DashboardRepository.Instance.GetDefault();
	if(SubscriptionContext.Instance.IsToggleEnabled("Generate Reports").Value)
	{
		configuredDashboard.GenerateReports();
	}
	return configuredDashboard;	
}

As shown in these examples, it is important to determine Feature granularity.  Once one has a conceptual grasp on how granular a Feature is, the appropriate API level construct can be used.

Boundary Features are slightly more interactive and are useful for tracking Features that rely on subscribed values to determine access. Similar to Toggle Features, Boundary Features have both attribute and direct API call constructs, albeit the attributes are significantly richer in behavior and applicability than that offered by Toggle Features. Boundary Features are governed by two attributes: a BoundaryFeature attribute tying the operation to a named boundary, and a BoundaryCheck attribute tying an argument in that operation to rejection behavior. Currently, the boundary attribute can be applied to service method parameters that are enumerable in nature (such as arrays/collections) or to primitive real number values. When applied to an enumerable, the attribute will flag Apprenda to check the size of the item container against the subscribed value. When applied directly to a value, a value-to-value comparison occurs. Rejection is determined by supplying the attribute with a BoundaryRejection enum value that instructs Apprenda how to interpret violations and allowances.

C# Example – Boundary Features

//Attribute applied to the value ‘fileSize’ with instructions to 
//reject the call if ‘fileSize’ is greater than the current user’s 
//subscribed “File Upload” value
[OperationContract]
[BoundaryFeature("File Upload")]
public void UploadFile(File file, 
    [BoundaryCheck(BoundaryRejection.IfGreaterThan)] long fileSize)
{
    FileStorage.Save(file);
}

//Attribute applied to an array of bytes instructions with 
//instructions to reject the call if size of ‘data’ is greater 
//than the current user’s subscribed “File Upload” value
[OperationContract]
[BoundaryFeature("File Upload")]
public void UploadFile(File file, 
    [BoundaryCheck(BoundaryRejection.IfGreaterThan)] byte[] data)
{
    FileStorage.Save(file, data);
}

//Non-attribute boundary checking
[OperationContract]
public void AttachHelpTicketToAsset(HelpTicket ticket, Guid assetId)
{
    if(false == SubscriptionContext.Instance.IsBelowBound
    ("Ticket Attachment Size", ticket.Attachment.Size).Value)
      {
        throw new BoundaryViolatedException("Too big");
    }           
    Asset asset = AssetRepository.Instance.Get(assetId);
    asset.Tickets.Add(ticket);
}

Interpreting boundary violations is up to the engineer. Some Boundary Features might represent minimums, while others represent maximums.

Limiter Features represent a meterable construct. Limiters maintain rolling counts of some action. The count can be debited from or credited to. For example, an application can allow only a certain number of some item type to exist concurrently. Once some maximum is reached, Apprenda will report that the Feature has been exhausted. A common example is a project management application allowing for a certain number of concurrently open projects. Limiter debiting and crediting can either be controlled declaratively with attribute signatures on WCF service methods, or via direct API calls.

C# Example – Limiter Features

//Attribute to increment the metered count for the “Projects” feature
[OperationContract]
[IncrementLimiter("Projects")]
public void CreateProject(Project project)
{
    ProjectRepository.Instance.Save(project);
}

//Attribute to decrement the metered count for the “Projects” feature 
[OperationContract]
[DecrementLimiter("Projects")]
public void DeleteProject(Project project)
{
    ProjectRepository.Instance.Delete(project);
}

//Non-attribute limit checking and manipulation
[OperationContract]
public void CreateSpecialProject(Project specialProject)
{
    MeterStatus status = SubscriptionContext.Instance
                .IncrementLimitCounter(”Projects”);

    if (MeterStatus.Exhausted == status)
    { 
        SubscriptionContext.Instance
            .DecrementLimitCounter(”Projects”);

        throw new LimiterExhaustedException(
        “Projects”, status, 
        "Unable to create another project as your limit has been reached");   
    }

    ProjectRepository.Instance.Save(specialProject);
}

 
Block Features are meterable Features that represent pre-allocated quantities of some use case. For example, if an Apprenda application allows for sending SMS messages or analysis of images for object recognition, one may wish to pre-allocate a certain number of units to a Tenant group.  As Users use the Feature, a metered deduction occurs. Currently, block credits and deductions are available through the Apprenda API via direct method calls. See the Apprenda API documentation for more information.

C# Example – Block Features

//Attribute to decrement the remaining block of SMS messages
[OperationContract]
[DecrementBlock("Messages")]
public void SendMessage(Message message)
{
    MessageQueue.Send(message);
}

//Non-attribute block checking and manipulation
[OperationContract]
public void SendMessage(Message message)
{
    MeterStatus status = SubscriptionContext.Instance
        .DecrementBlock("Messages");

    if (MeterStatus.Exhausted == status)
    { 
        SubscriptionContext.Instance
            .IncrementBlock(”Messages”);

        throw new BlockExhaustedException(
        "Messages", status, 
        "Unable to send another message until you purchase additional messages. ");
    }
    MessageQueue.Send(message);
}

Working with Features in the Java Guest App API

The four types of Features supported for .NET guest applications are also supported for Java applications.

Examining Features

import com.apprenda.guest.access.BlockMeter;
import com.apprenda.guest.access.BoundMeter;
import com.apprenda.guest.access.LimitMeter;
import com.apprenda.guest.access.ToggleMeter;
import com.apprenda.guest.api.ApprendaGuestApp;
import com.apprenda.guest.api.GuestAppContext;
import com.apprenda.guest.api.AppVersion;
import com.apprenda.guest.api.Meters;
 
// in your code
GuestAppContext guestCtx = ApprendaGuestApp.getContext();
if (guestCtx.isAuthorizationEnabled()) {               
    AppVersion appVersion = guestCtx.getAppVersion();
    Meters meters = guestCtx.getMeters();
    BlockMeter blockMeter = meters.getBlock("Number of Support Emails");
    BoundMeter boundMeter =  meters.getBound("Max Attachment Size");
    LimitMeter limitMeter =  meters.getLimit("Number of Tasks");
    ToggleMeter toggleMeter =  meters.getToggle("Priority Management"));
}

Interacting with the meters is quite straightforward: retrieve a meter reference, then either check or manipulate its status. Further information can be found in the API docs for BlockMeterBoundMeterLimitMeter, and ToggleMeter

GuestAppContext guestCtx = ApprendaGuestApp.getContext();
// support responded to one more support email out of the support emails supported by the plan, decrement the block meter to record it, when it hits zero it will become exhausted
BlockMeter blockMeter = guestCtx.getMeters().getBlock("Number of Support Emails");
blockMeter.decrement(1);
 
// the user just created two new tasks, record the number of tasks so that the user cannot exceed his maximum limit of tasks, when the user hits that ceiling the meter becomes exhaused
LimitMeter limitMeter = guestCtx.getMeters().getLimit("Number of Tasks");
limitMeter.increment(2);
 
// based on their service plan, users can attach different sizes of files to their tasks
File attachment ; // retrieve the attachment that the user is trying to upload - your own code
BoundMeter boundMeter = guestCtx.getMeters().getBound("Max Attachment Size");
boolean isAllowedAttachmentSize = boundMeter.isAboveBound(file.length());
 
// check if this user's plan has this feature enabled - only the Gold plans have the ability to prioritize
ToggleMeter toggleMeter = guestCtx.getMeters().getToggle("Priority Management");
boolean isFeatureEnabled = toggleMeter.isEnabled():