Obsolete Pages{{Obsolete}}
The official documentation is at: http://docs.alfresco.com
Core Repository ServicesOverviewJava_API
The Services Framework provides a pattern for encapsulating Repository behaviour at the Service, Aspect and Type level.
Support the following Repository developer roles:
Service Implementors are Java developers. The Services Framework provides them a pattern for defining, implementing and exposing the Repository API (i.e. Repository Services). The pattern promotes an extensible and pluggable Repository architecture.
Content Modellers are knowledgeable of the business domain. Technical knowledge varies. From least to most technical there are:
The Service Framework is not responsible for maintaining Content Type meta data. Instead, the Type Mechanism component will provide meta data definition and query. Out of the box, the Repository is pre-installed with Content Type meta data for common content scenarios, such as File System & Collaboration.
The Service Framework interacts closely with Content Type meta data to bring Types to life! That is, it provides a mechanism for tying behaviour to Types. To support this, the framework provides:
Application developers are technically oriented. However, the Repository should provide access for all types of application developers - enterprise, LAMP and .NET.
The Service framework allows:
The public Repository API is a collection of service oriented interfaces. Each service is named and has an associated Java interface. Each Repository exposes a Service registry allowing a client to examine the list of available services. A core set of well-known services are packaged by default. New services may be deployed extending the capabilities of the Repository. Clients access a service by name.
Note: A service oriented API (as opposed to a fully object-oriented API) provides a relatively simple interface to Repository services (similar to WebDAV). It lends itself towards a stateless approach, and as such, each method on an interface requires all state to be passed in e.g. any objects to operate on.
Service interfaces are backed by an implementation component. Typically, this is a Java class, but could also be script. The Service registry identifies the implementation component for each service. This indirection allows the implementation of any service to be switched without client knowledge.
A component may also be implemented as an internal Repository building block. In this case, it is not registered with any public Service, but can be still be referred to internally.
Components depend on other components; dependencies are resolved via dependency injection.
There are two different type of Component: ServiceComponent and ClassComponent. Either can be exposed a public Repository Service.
A Service Component is one which is not directly tied to any particular class in the meta model e.g. Node_Service (Object CRUD) or Search.
A Class based Component is one which is tied to a specific class in the meta model. The class may be a Type or Mixin, although it's much more useful for Mixin. The exposed component API provides class specific behaviour e.g. Folder, Version or Lock. When tying a Component to a Mixin, it's possible to provide automatic introduction of the Mixin to any Nodes that are operated on by the Component. This is controlled by the ClassBinding value in the above diagram:
Note: The apply behaviour can only be supported by a Repository whose implementation supports the introduction of a Mixin to a node at run-time.
Component implementations may defer to Content Types to allow for model specific behaviour to be injected into their process. The component implementor is responsible for the contract which describes how to inject and when to inject. This contract is known as a 'policy'. For example, the Node component may define policies such as onCreateNode, beforeDeleteNode, onUpdateProperties, etc. The CheckOutCheckIn component may define policies such as onCheckOut, onCheckIn, onCancelCheckOut, etc.
Each policy is named extends one of the following interfaces: ClassPolicy, AssociationPolicy or PropertyPolicy. The contract is defined via the 'Policy' Java Interface.
The registration of policies is performed during Component initialisation. An internal Repository component (PolicyComponent) provides the interface for registration.
Note: It is unlikely that there will be a persistent representation of policies. A Repository can be queried for a list of registered policies, but that list will depend on the initialised components/services. Content Type meta data (including behaviour) will be persisted and may be transferred from one Repository to another. It's possible for a Content Type to support a behaviour for a policy which is not registered (because it does not support the service which defines the policy). In this case, the Repository will ignore the behaviour.
Model behaviours are snippets of logic which provide Content Type specific behaviour for a given policy. The logic may be encapsulated within a Java class (which supports the policy defined Java interface) or script. Service implementors are likely to provide Java implementations, whilst Content Modellers are likely to provide Script implementations.
In the scripting case, the script must provide the appropriate function(s) to fulfill the Java interface contract. JSR 223 (and BSF) provide mechanisms to present a Java interface facade on top of a script. Note: It is not clear if the Content Modeller will need to provide the complete function definition in the script, or whether the Repository can generate a function wrapper around their hand-coded logic.
Behaviours may have dependencies on Repository Services. Java developers can use standard Dependency Injection techniques. Script developers can be provided with well known global variables; one for each published Repository Service.
Registration of behaviours is performed through an internal Repository component (PolicyRuntimeService). This can be achieved programmatically or driven by Content Type meta data developed by hand or generated by an administration tool. The PolicyRuntimeService is also responsible for dynamically dispatching to the appropriate behaviour based on Content Class (Type and Aspect) and in the future, possibly other context values.
Not every component is exposed as a public service, and this is true for a Class based component too. An internal class component allows for default type specific behaviours to be encapsulated and registered with the Repository (during the class component initialisation). Typically, a Java implementation is chosen, allowing for sophisticated behaviours (which rely on obscure Java APIs or internal Repository components). Each behaviour could be implemented as an inner class.
This technique is particularly useful for Aspects which do not expose a specific public Repository API, but do encapsulate behaviour. For example, Dublin Core or Auditable. Each of these Aspects have a corresponding Mixin which define a set of attributes. The internal Class component can register behaviours for policies such as onChanged etc which automatically assign values to lastUpdatedDate or changedBy attributes as defined by the Mixin.
Default behaviours defined by Class components can still be replaced by scripted versions as defined by less technical Content Modellers.
By taking a Service oriented approach to our API, it is relatively easy to provide remote access to the Repository. In some cases, services may be remotable without change, but others may have to expose a simple facade to improve latency or serialization issues.
Exporting a Web Service layer allows for the Repository to be used in a much wider set of scenarios such as LAMP integration or business process integration.
The Content Type meta data schema has yet to be defined, but the assumption is that something similar to Paul's XML definition will exist.
There is a loose dependency on the Content meta-meta model. An assumption is that concepts such as Type def, Property def and Relationship def exist. The existence of such concepts will drive the Policy types available in the framework.
Node References and Store Protocols
The Service Registry provides a means for defining and discovering Repository services. Effectively, it's the equivalent of UDDI in the Web Services world.
/**
* Get Services provided by Repository
*
* @return list of provided Services
*/
List<string> getServices();
/**
* Is Service Provided?
*
* @param serviceName name of service to test provision of
* @return true => provided, false => not provided
*/
boolean isServiceProvided(string serviceName);
/**
* Get Service Meta Data
*
* @param serviceName name of service to retrieve meta data for
* @return the service meta data
*/
ServiceDescriptor getServiceDescriptor( string serviceName );
/**
* Get Service Interface
*
* @param serviceName name of service to retrieve
* @return the service interface
*/
Object getService(string serviceName);
//
// Core Service Locators (typed)
//
// Note: May return null if service is not provided
//
WorkspaceService getWorkspaceService();
NodeService getNodeService();
ContentService getContentService();
SearchService getSearchService();
VersionService getVersionService();
LockService getLockService();
string Service Name
class Service Interface Class
string Author
string Version
store[] Supported Store Protocols??
ServiceRegistry registry = applicationContext.get('ServiceRegistry');
ServiceRegistry registry = new DefaultServiceRegistry(BeanFactory serviceFactory);
The Service Framework can utilise Spring as follows:
Initially, the definition of Repository components/services etc will be expressed using Spring syntax. This will effectively expose Spring to the Service Implementor role. However, with the introduction of Spring 1.2? (XML schema support) it will be possible to define a Content Repository specific XML schema for the definition of components and services. At this point, it won't be necessary to expose the Spring dependency to our development community.
An example generic service (i.e. not tied to a specific class definition)...
Name: Node
Interface: org.alfresco.repository.NodeService (java)
Implementation: DefaultNodeService (name of component implementing the interface)
Example interface (see Node Service API Design for detail)...
id createNode(workspace, parent, name, type, ...)
void setProperties(workspace, node, properties, ...)
Example component:
Name: DefaultNodeService
Implementation: org.alfresco....NodeServiceImpl (java)
Dependencies: PolicyDefinition, PolicyRuntime
An example aspect based service...
Name: Lock
Interface: org.alfresco.repository.Lock (java)
Implementation: DefaultLockAspect (name of component implementing the interface)
ClassBinding: Lock Aspect Definition + auto apply aspect
Example interface (see Lock Aspect for detail)...
lock(workspace, node, owner, ...)
release(workspace, node, ...)
Example component:
Name: DefaultLockAspect
Implementation: org.alfresco....LockAspectImpl (java)
Some example Policies exposed via the Node Service implementation...
Name: onCreate
Type: Class
Interface: org.alfresco.repository.NodeService.CreatePolicy
Name: beforePropertyChanged
Type: Property
Interface: org.alfresco.repository.NodeService.BeforePropertySetPolicy
Example CreatePolicy interface...
void onCreate(workspace, node, ...)
Example BeforePropertySetPolicy interface...
void beforePropertySet(workspace, node, property, newvalue, ...)
Example registration of policies (by NodeService implementation)...
public init()
{
// policyDefinitionComponent set via Dependency Injection
policyDefinitionComponent.registerClassPolicy(this, CreatePolicy.class);
policyDefinitionComponent.registerPropertyPolicy(this, BeforePropertySetPolicy.class);
}
Example declarative registration of (scripted) behaviour (note: the exact form of registering Content Type meta data has yet to be defined)...
<type name='File'>
<property name='name'>
...
<beforePropertyChanged>
if newValue.contains('.')
throw new Exception('File name ' + newValue + ' is invalid - it cannot contain a full stop');
</beforePropertyChanged>
</property>
</type>
The above declaration expands to the following registration...
policyRuntimeComponent.registerPropertyBehaviour(type.File, property.name, new ScriptedBehaviour(...));
Example invocation of behaviour from service implementation...
BeforePropertyChangedPolicy behaviour
= policyRuntimeComponent.getPropertyBehaviour('beforePropertyChanged',
node | type, property);
behaviour.beforePropertySet(workspace, node, property, value);
Note: We could possibly make use of Java 1.5 generics to support the above registration and retrieval of Policy specific interfaces.
Example of an Aspect based component which itself does not expose a public interface, but does provide default behaviour for the aspect...
Name: DefaultAuditableAspect
Implementation: org.alfresco.repository...DefaultAuditableImpl (java)
ClassBinding: Auditable Aspect definition
Example implementation (in java, but could equally be defined in script too)...
public class DefaultAuditableImpl
{
// provide setters for dependency injection
public void setSessionManager(SessionManager sessionMgr) ...
public void setNodeService(NodeService nodeService) ...
public class AuditableCreatePolicy implements CreatePolicy
{
public void onCreate(...)
{
nodeService.setProperty(workspace, node, 'createdDate', now);
nodeService.setProperty(workspace, node, 'createdBy', sessionMgr.getOwner());
}
}
public class AuditableSetPropertyPolicy implements SetPropertyPolicy
{
public void onSetProperty(...)
{
if (property.name != 'updatedDate')
nodeService.setProperty(workspace, node, 'updatedDate', now);
}
}
public class AuditableIntroducePolicy implements IntroducePolicy
{
public onIntroduction(...)
{
nodeService.setProperty(workspace, node, 'auditStartDate', now);
}
}
public void init()
{
policyRuntimeComponent.registerClassBehaviour(type.Auditable, new AuditableIntroducePolicy());
policyRuntimeComponent.registerClassBehaviour(type.Auditable, new AuditableCreatePolicy());
policyRuntimeComponent.registerPropertyBehaviour(type.Auditable, property.*,
new AuditableSetPropertyPolicy());
}
}