Policy Component

From alfrescowiki

Jump to: navigation, search


Contents

Introduction

See Services Framework#Component Policies for description of Policies.

The Policy Component allows:

  • Service Implementors to register policy definitions (i.e. expose policies)
  • Service Implementors/Content Modellers to bind behaviour to policies
  • Service Implementors to invoke bound behaviour

Policy Definition

Each Policy is defined as an interface with a single method. A Policy is either of type Class, Property or Association which is indicated by inheriting from one of the following marker interfaces:

  • ClassPolicy
  • PropertyPolicy
  • AssociationPolicy

Policy method parameters define the state available to each bound behaviour. Policy method return values define the expected results of a behaviour.

Examples:

 interface CalculateVersionLabelPolicy extends ClassPolicy
 {
   String calculateVersionLabel(QName classRef,
                                Version preceedingVersion,
                                int versionNumber,
                                Map<String, Serializable> versionProperties);
 }
 interface BeforeCreatePolicy extends ClassPolicy
 {
   void beforeCreate(ClassRef classRef);
 }
 interface BeforeSetPropertyPolicy extends PropertyPolicy
 {
   void beforeSetProperty(QName property, Serializable newValue);
 }

Policy Meta-Data

The following policy meta-data is supported:

  • Namespace - Policy Namespace used when binding behaviour to the policy
  • (future) Group - Policy group

Annotations

Future support will allow for meta-data provision via Annotations.

Example:

 @Policy(namespace="namespaceURI")
 interface VersionLabelPolicy extends ClassPolicy
 {
   string getVersionLabel(NodeRef node);
 }

Static Variables

Current support will allow for meta-data provision via static variables.

Example:

 interface VersionLabelPolicy extends ClassPolicy
 {
   static String NAMESPACE = "namespaceURI";
string getVersionLabel(NodeRef node); }

Registering Policy Definitions

Policies are registered during the initialisation of a Service using the PolicyComponent (injected via DI).

Example:

 public void NodeService
 {
   private ClassPolicyDelegate<BeforeCreatePolicy> beforeCreateDelegate;
public void init() { beforeCreateDelegate = policyComponent.registerClassPolicy(BeforeCreatePolicy.class); } ... }

The PolicyComponent updates its registry of available Policies by interrogating the passed Policy interface (and associated meta-data). A Policy is registered for each method.

Registration returns a PolicyDelegate (parameterized by the passed Policy Interface). The service keeps hold of the delegate to invoke Policies.

Register APIs

  public interface PolicyComponent
  {
    ....
    public <P extends ClassPolicy> ClassPolicyDelegate<P> registerClassPolicy(Class<P> policy);
    public <P extends PropertyPolicy> PropertyPolicyDelegate<P> registerPropertyPolicy(Class<P> policy);
    public <P extends AssociationPolicy> AssociationPolicyDelegate<P> registerAssociationPolicy(Class<P> policy);

    public Collection<PolicyDefinition> getRegisteredPolicies();
    public PolicyDefinition<Policy> getRegisteredPolicy(PolicyType policyType, QName policy);
    public boolean isRegisteredPolicy(PolicyType policyType, QName policy);
    ....
  }

Please refer to JavaDoc for more details.

Invoking a Policy

A Service invokes a Policy via the PolicyDelegate. Given an appropriate context (e.g. ClassRef for a ClassPolicy), the PolicyDelegate returns a bound implementation of the registered Policy interface.

The service then calls the appropriate Policy method(s) on the interface to invoke any registered behaviour for that context.

Example:

 public void NodeService
 {
    public NodeRef createNode(...)
    {
       ...
       BeforeCreatePolicy policy = beforeCreateDelegate.get(nodeClassRef);
       policy.beforeCreate(nodeClassRef);
       ...
    }
 }

A Service does not necessarily concern itself with how many behaviours are registered with the policy for a given context. It may be that none, one or many have been registered. In any case, the above code applies.

However, there are some scenarios where a service may wish to have more control over the behaviours invoked. For example, a Policy may have a return value, or a service may want control over prioritisation, conflicts etc. In this case, the delegate provides an alternate form of get where an array of Policy interfaces is returned (one for each registered behaviour).

Example:

 public void NodeService
 {
    public NodeRef createNode(...)
    {
       ...
       BeforeCreatePolicy[] policies = beforeCreateDelegate.getList(nodeRef);
       for (policy in policies)
       {
         policy.beforeCreate(nodeClassRef);
       }
       ...
       AfterCreatePolicy[] policies = beforeCreateDelegate.getList(nodeRef);
       for (policy in policies)
       {
         policy.afterCreate(nodeClassRef);
       }
    }
 }

Delegate APIs

 class ClassPolicyDelegate<T extends ClassPolicy>
 {
   T get(ClassRef classRef);
   T get(NodeRef nodeRef);
   T[] getList(ClassRef classRef);
   T[] getList(NodeRef nodeRef);
 }
 class PropertyPolicyDelegate<T extends PropertyPolicy>
 {
   T get(ClassRef classRef, QName property);
   T get(NodeRef classRef, QName property);
   T[] getList(ClassRef classRef, QName property);
   T[] getList(NodeRef classRef, QName property);
 }
 class PropertyPolicyDelegate<T extends AssociationPolicy>
 {
   T get(ClassRef classRef, QName association);
   T get(NodeRef classRef, QName association);
   T[] getList(ClassRef classRef, QName association);
   T[] getList(NodeRef classRef, QName association);
 }

Note:

  1. Property and Association naming scheme to be changed at some point

Binding Behaviour to a Policy

Behaviour can be bound to a policy using the PolicyComponent. Typically, behaviour is associated with a given Type or Aspect in the Content Domain Model. But in some scenarios, the behaviour may not be type specific, and as such, is always applied.

Example:

 public void FolderComponent
 {
   public void init()
   {
     policyComponent.bindBehaviour("alf:getVersionLabel", new ClassBinding("alf:Folder"), 
        new JavaBehaviourDelegate(this, "getVersionLabel"));
   }
   
private string getVersionLabel(NodeRef ref) { ... } }

The bindBehaviour method takes the following arguments:

policyName - name of policy (as registered) to bind to
binding - the context in which the behaviour applies (can also be Property and AssociationBinding) or null (always apply)
behaviourDelegate - pointer to the behaviour (default Java, but could also be ScriptedBehaviourDelegate)

Binding APIs

  public interface PolicyComponent
  {
    ....
    public BehaviourDefinition<ClassBehaviourBinding> bindClassBehaviour(QName policy, QName className, Behaviour behaviour);
    public BehaviourDefinition<ServiceBehaviourBinding> bindClassBehaviour(QName policy, Object service, Behaviour behaviour);

    public BehaviourDefinition<ClassFeatureBehaviourBinding> bindPropertyBehaviour(QName policy, QName className, QName propertyName, Behaviour behaviour);
    public BehaviourDefinition<ClassFeatureBehaviourBinding> bindPropertyBehaviour(QName policy, QName className, Behaviour behaviour);
    public BehaviourDefinition<ServiceBehaviourBinding> bindPropertyBehaviour(QName policy, Object service, Behaviour behaviour);

    public BehaviourDefinition<ClassFeatureBehaviourBinding> bindAssociationBehaviour(QName policy, QName className, QName assocName, Behaviour behaviour);
    public BehaviourDefinition<ClassFeatureBehaviourBinding> bindAssociationBehaviour(QName policy, QName className, Behaviour behaviour);
    public BehaviourDefinition<ServiceBehaviourBinding> bindAssociationBehaviour(QName policy, Object service, Behaviour behaviour);

    ....
  }

Please refer to JavaDoc for more details.

Policy and Behaviour Dependencies

There is no enforced compile-time dependency between a behaviour provider and policy provider. This allows services, aspects and types to be plugged in and out of a Repository (i.e. install/de-install) without breaking code.

Components can bind behaviours without the policy having been registered (or exist), and services can invoke policies without there being any bound behaviour. Warnings etc can be given in these scenarios.

However, there may be cases where it does not matter that code dependencies exist between behaviour and policy (e.g. behaviours registered for core NodeService policies). In these cases, the behaviour implementor can always import the policy interface and implement it on the their behaviour class to ensure compile time checks of method signatures.

Personal tools
Download and go
© 2014 Alfresco Software, Inc. All Rights Reserved. Legal | Privacy | Accessibility