The Annotation Web services API is an implementation-neutral set of SOAP-based Web services calls intended as an industry standard to facilitate the interoperability of clients who wish to enable annotations and servers that store annotations and implement the API. The Web services Definition Language (WSDL) formally defines the syntax of the API. There are accompanying semantics in another document. This article explains the motivations behind the API’s design, as well as an overview of the API. You should consult the WSDL and accompanying semantic documentation for more information (see the Resources section below for links).
The word annotation has many different meanings depending upon the context and audience. Regardless of these differences, every annotation is essentially some metadata associated with some target data. The target data itself can vary from a table in a relational database, to a word processing document, or to the topic of what to cook for dinner tonight. The corresponding annotation might be an entry in another database table, a comment within the document, or a sticky note on the front of the refrigerator. Annotations are important when large amounts of data are created, shared, and examined. For example, the life sciences industry and the legal profession both make heavy use of annotations.
Everything but the refrigerator
Because of the substantial generality of annotations, the scope of the design must be narrowed in order to arrive at a useful and manageable Annotation Web services API. To accomplish this, the goals of a system must be enumerated based upon the Annotation Web services API and then derive the data model and API calls from those goals.
Annotate arbitrary digital data
The primary goal of the Annotation Web services API is to enable the annotation of any arbitrary digital data. Please note that the type, size, structure, or content of the data is arbitrary. For example, the same Annotation Web services API methods facilitate annotating both legal briefs and scientific experiment results.
Annotations stored out-of-band
The API should acknowledge the intrinsic existence and identity of data objects regardless of their names, locations, or any properties other than their contents. In other words, an annotation that you create on a memo on your local hard drive should be visible to your coworker with his or her own copy of the memo, despite potentially differing meta-information such as file name or timestamp. To accomplish this, the Annotation Web services API must encompass a model in which the annotations are stored separately from target data objects and in which data objects' identities can be determined independently of file meta-information.
Many applications include annotation functionality that follows the "sticky note" paradigm. Such annotations are better referred to as comments, as they consist only of free-form text entries. Even when centrally gathered, these unstructured comments are difficult to search or data-mine effectively and efficiently. Therefore, one goal of the Annotation Web services API design is the support of structured annotations -- annotations containing information that conforms to a particular structure. Because a free-form text entry is simply one particular annotation structure, this design goal does not preclude unstructured annotations.
Several other goals also drove the design of the Annotation Web services API. Access control must be included to allow for private and semi-private annotations. The API must also facilitate bidirectional access between the annotations and the target data. The API also allows for maximum configuration, flexibility, and extensibility by implementors.
Having presented the goals of the Annotation Web services API, turn your attention now to the data model that defines the world in which the API operates. This data model consists of the objects needed to realize the design goals and the relationships between these objects. The API is responsible for create, query, update, and delete methods for these objects and relationships. XML complex-type data structures represent all of the objects and relationships, and WSDL gives the exact syntax of the structures.
An annotation structure is an XML document (a structure document) that defines one particular type of annotation. A Uniform Resource Identifier (URI) names every annotation structure. The URI identifies the annotation type defined by the structure. The annotation structure is an ordered collection of named fields, where each field defines one piece of data to be collected in an annotation conforming to the structure. Fields are typed using standard XML Schema data types; a field might be optional and can allow multiple values. Moreover, related fields might be grouped together. A field's definition might also include other meta-information, such as a human-readable label, a default value, help text, and a picklist of potential values for the field. The field definitions within an annotation structure might also contain an arbitrary number of facets, which are implementation-defined name-value pairs that provide full extensibility of the meta-information associated with a field. For example, a field might contain a facet that provides validation information, such as the maximum allowed length of a string field.
An annotation is an XML document (an instance document) that contains the actual data of an annotation. Every annotation has an associated annotation type, and the annotation is an instantiation of the corresponding annotation structure. In other words, an annotation specifies values for all of the fields defined by the annotation's structure. Within this API, annotations are identified by globally unique identifiers (GUIDs). Many annotations can share the same annotation type and structure.
A data object that might be the target of an annotation is referred to as a data source. The data model's data source construct represents a set of bytes independent of their location, as discussed earlier in the section on API design goals. Within the Annotation Web services API, opaque string identifiers represent data sources. An implementation should define the exact semantics of data source identifiers; however, it must be possible to determine a data source identifier directly from the bytes that comprise the data source. For example, an implementation might define a data source identifier as the computed MD5 hash value of the data source's bytes.
Every data source has a data source type (represented as a URI) indicating the type of the underlying data object (database, word processing document, spreadsheet, and so forth). Data sources can also have an optional subtype specifying the type of semantic content of the data object (inventory, human resources, research experiment, and so forth). The Annotation Web services API uses both the data source type and subtype. This allows for more precise choice of annotation structure and more flexible annotation retrieval.
A point is a typed series of name-value pairs -- known as point properties -- that specifies the location of an annotation within a data source. The type of the point (and, as with data sources, an optional semantic subtype) tells client software how to interpret the properties of the point. For example, a spreadsheet data source type might contain an annotation on points with type cell, and the properties of this point might contain the row and column to which the annotation applies.
The scope of an annotation consists of the data source types, data source subtypes, point types, and point subtypes of the points being annotated. The Annotation Web services API allows different annotation structures to correspond to different scopes.
A data source descriptor is not a base unit of the data model. Instead, it is a data structure that represents the relationship of all of the data source information relevant to one particular annotation. It consists of information defining the data source (identifier, data source type, and optional data source subtype), zero or more actual locations (file paths, URLs, and so forth) at which the data source might be found, and one or more points within this data source that are annotated by the relevant annotation. Thus, the data source descriptor defines two distinct relationships. First, it defines a one-to-many relationship between a data source and the locations of the data source. This relationship is independent of any particular annotation. Second, the data source descriptor defines the point or points within the data source to which one particular annotation applies. If the annotation targets multiple data sources, there might be a relationship between a single annotation and multiple data source descriptors.
Principals are the core unit of the API's access control system. A principal is either a user or a semantically-related group of users, known as a role. The XML structure of a principal includes an identifier, the type of principal (user or role), and a human-readable name and description of the principal.
The Annotation Web services API defines two different access-control lists. First, each field defined by an annotation structure has an associated access-control list that specifies the principals that might read (view) and write (edit) the values in that field. An XML document represents these field-level permissions and is commonly referred to as an ACLs document. These permissions allow different users to have different views of the same annotation. Access-control lists based on principals are also applied to individual annotations. The Annotation Web services API allows for any principal in the system to have zero or more of the read, write, delete, or manage (update permissions) actions for a particular annotation. Furthermore, implementations can define additional actions that might be restricted via the annotation-instance access control lists. The precise rights that a given principal has for a given annotation and its fields are the intersection of that principal's field-level and instance-level access for that annotation and corresponding structure.
Manipulating the building blocks
The Annotation Web services API consists of 29 methods with which an annotation client can communicate with an annotation server in order to create, update, and retrieve the objects discussed so far. The WSDL formally defines the syntax of the API, and another document covers the semantics. This section of the article presents an overview of the methods and the way in which they fulfill the Annotation Web services API's design goals.
In the following listings, brackets "[ ]" represent arrays and a colon ":" separates input parameters from return values.
Listing 1. Session management methods
Login(StringDictionary credentialParts, string clientVersion, string locale,
StringDictionary clientProperties) :
string sessionKey, string serverVersion, StringDictionary systemProperties
Logout(string sessionKey) |
A user must authenticate with an annotation server in order to get the session key token that all other methods in the API require. The Login() method also allows for both the client and server to indicate the version of the Annotation Web services API that they support, as well as arbitrary, implementation-defined properties. The Logout() method invalidates the supplied session key.
Listing 2. Principal management methods
QueryPrincipals(string sessionKey, string type) : Principal[] principals SetRoles(string sessionKey, string[] roles) |
QueryPrincipals() allows an annotation client to retrieve -- depending on the value of the type parameter -- all the principals defined in the system, the current user's available principals, or the principals that are currently active for the current user. Similarly, SetRoles() allows the logged-in user to act in some or all of his or her available roles for the purpose of the ACLs application and annotation structure selection.
Listing 3. Data source and point management methods
QueryDataSourceSubtypes(string sessionKey, string dataSourceType) :
string[] dataSourceSubtypes
QueryAllowedPointTypes(string sessionKey, string dataSourceType,
string dataSourceSubtypes) : (string pointType, string pointSubtype)[]
QueryPoints(string sessionKey, string guid) : DataSourceDescriptor[] descriptors
AddPoints(string sessionKey, string guid, DataSourceDescriptor[] descriptors
Attachment[] attachments)
DeletePoint(string sessionKey, string guid, string dataSourceId, Point point)
QueryDataSourceLocations(string sessionKey, string dataSourceId) :
string[] locations
AddDataSourceLocation(string sessionKey, string dataSourceId, string location)
DeleteDataSourceLocation(string sessionKey, string dataSourceId, string location) |
The client can determine the data source subtypes configured for a particular data source type and the point types that might be annotated for a given data source type and subtype using QueryDataSourceSubtypes() and QueryAllowedPointTypes(). Clients use these methods to determine a server's configuration. For example, a client might learn from these methods that annotations are not allowed on a full column within an inventory spreadsheet.
QueryPoints(), AddPoints(), and DeletePoint() provide functionality that a client can use to retrieve and manage the points to which a particular annotation refers. Similarly, QueryDataSourceLocations(), AddDataSourceLocation(), and DeleteDataSourceLocation() allow a client to retrieve and manage the physical locations at which a data source might be found.
Listing 4. Annotation structure management methods
QueryStructureNames(string sessionKey, string queryQualifier, Scope[] scope) :
(string description, string title, URI structureName)[]
GetStructure(string sessionKey, URI structureName) :
StructureDocument structure, ACLsDocument accessControl
QueryStructureTransforms(string sessionKey, URI structureName) :
URI url, URI input, URI output, string description, string title |
The three API methods in Listing 4 provide the information necessary for an annotation client to render an annotation structure for a user. The client can retrieve the structures that are valid for the current user and for the scope being annotated via QueryStructureNames(), which returns valid structure names along with a human-readable title and description for each. The client can use GetStructure() to retrieve the structure document and the ACLs document for the given structure name. The last step in rendering an annotation structure is to use an XSL transform to produce viewable output. The method QueryStructureTransforms() returns the URLs to zero or more XSL transforms configured to render the specified annotation structure. The meta-information specifies the input format that a transform knows how to process and the output format that it produces (for example, HTML, XForms, and so forth) along with a human-readable title and description. The client selects the transform to apply based upon the target display and the input formats it knows how to produce from the structure document, ACLs document, and, if applicable, the annotation itself.
Listing 5. Annotation management methods
CreateAnnotation(string sessionKey, InstanceDocument annotation,
DataSourceDescriptor[] descriptors, AccessControlList instanceACLs,
Attachment[] attachments) : string guid
ReplaceAnnotation(string sessionKey, string guid, InstanceDocument annotation,
string oldVersion, Attachment[] attachments) : string newVersion
DeleteAnnotation(string sessionKey, string guid)
QueryAnnotationIds(string sessionKey, string dataSourceType,
string dataSourceSubtype, Point point, string location, string[] dataSourceIds) :
string[] guids
QueryAnnotationDescriptions(string sessionKey, string dataSourceType,
string dataSourceSubtype, Point point, string location, string[] dataSourceIds) :
(string guid, DataSourceDescriptor[] descriptors)[]
QueryAnnotationHistory(string sessionKey, string guid) : string[] versions
GetAnnotation(string sessionKey, string guid, string version,
string[] includeFields) : InstanceDocument annotation, string[] allowedActions,
string version, string[] attachmentIds
GetAnnotations(string sessionKey, string[] guids, string[] includeFields) :
(InstanceDocument annotation, string[] allowedActions, string version,
string[] attachmentIds)[]
QueryPermission(string sessionKey, string guid) : AccessControlList instanceACLs
SetPermissions(string sessionKey, string guid, AccessControlList instanceACLs)
RetrieveAttachmentData(string sessionKey, string guid, string attachmentId) :
Attachment attachment |
Creating an annotation involves passing an instance document, the data source descriptors that indicate the annotation's target, and the permissions on the annotation from the client to the server. The data and permissions on an annotation can be replaced using ReplaceAnnotation() and SetPermissions(), respectively. The annotation permissions can be retrieved using QueryPermission(), and annotation data can be retrieved either singularly or in a batch mode using GetAnnotation() or GetAnnotations(). Annotations can be located via QueryAnnotationIds() and QueryAnnotationDescriptions(), which allow implementation-defined search semantics to be applied to the target data search criteria passed to the methods.
Annotations are versioned, and you can retrieve old versions of annotations using GetAnnotation(). QueryAnnotationHistory() retrieves a list of the versions of an annotation, and ReplaceAnnotation() takes as input the version of the annotation being replaced. As a result, a server can prevent the race condition in which a user retrieves and edits an annotation that has been updated by another user since it was retrieved.
Both point properties and annotation data might contain large amounts of binary data. To make this data manageable, the Annotation Web services API allows attachment IDs to be stored inline in the point properties or field values, and an extra attachments parameter sends the appropriate binary data associated with the attachment ID. The method RetrieveAttachmentData() facilitates the retrieval of this binary data.
Listing 6. Miscellaneous methods
SetLocale(string sessionKey, string locale) QueryUserSettings(string sessionKey, string applicationId) : string settings SetUserSettings(string sessionKey, string applicationId, string settings) |
SetLocale() allows an annotation client to change the locale that was originally specified on the Login() call. QueryUserSettings() and SetUserSettings() allow client applications to store and retrieve arbitrary user data on the server.
Using the Annotation Web services API
This section uses a hypothetical annotation client to cover two common uses of the API . The first example shows the API call sequence involved when a user opens a data source and chooses to view an annotation. The second shows possible steps to allow a user to create a new annotation. Both are examples, and different clients of the Annotation Web services API might have differing implementations. For the sake of simplicity, the examples do not account for checking and setting permissions on annotations. Please note that the details of determining the data source identifiers, data source types, point information, and even the order of the API method calls vary from implementation to implementation. The examples below cover two potential API uses.
Example 1. Displaying an existing annotation
- The user picks a file, f, to open.
- The annotation client calculates the MD5 hash of the contents of f, MD5f, and also determines the data source type,
dsType, from the file extension, database connection string, or other appropriate contextual information. The client callsQueryAnnotationDescriptions()and supplies MD5 f anddsTypeas search parameters. The server replies with the GUIDs and data source descriptors all of the matching annotations, and the client uses the point information to tell the user where annotations exist in the file. - The user asks to be shown the first annotation with GUID G.
- The client retrieves the instance document for this annotation by passing G to
GetAnnotation(). - The client retrieves the name of the corresponding annotation structure, S, and retrieves both the structure document and ACLs document by passing S to
GetStructure(). - The client retrieves an appropriate XSL transform by passing S to
QueryStructureTransforms(). - By combining the instance document, structure document, and ACLs document into a single (implementation-defined) XML format, the client uses the XSL transform to generate an HTML view of the annotation that is then shown to the user.
Example 2. Creating a new annotation
- The user, working with file f, indicates an area of the file that he or she wishes to annotate.
- The annotation client translates the area selected into an annotation point, P, determining the point type and properties based upon the area indicated by the user.
- As above, the annotation client determines the data source type,
dsType, and MD5 hash, MD5f, of the file. The annotation client asks the user to choose the semantic content of the annotation target area from the data source subtypes returned by passingdsTypetoQueryDataSourceSubtypes(). The user chooses a subtype,dsSubtype. - The annotation client ensures that the server allows this type of annotation by passing
dsTypeanddsSubtypetoQueryAllowedPointTypes()and checking that the point type information of P is in the returned list. - The annotation client asks the user to choose an annotation structure to use from the choices returned by passing
dsType,dsSubtype, and the point type of P toQueryStructureNames(). The user chooses a structure, S. - As in the first example, the client uses S to retrieve a structure document, ACLs document, and XSL transform for this structure.
- Since there is no existing annotation, the client creates a skeletal, blank instance document from the structure document so that all three documents can be fed to the XSL transform. This time, the transform produces an HTML form to allow the user to enter the annotation information.
- When the user submits the annotation, the annotation client retrieves the data from the HTML form and constructs an instance document. The client also constructs a data source descriptor from
dsType,dsSubtype, P, MD5f, and the location of f. The instance document and data source descriptor are passed toCreateAnnotation()to create the annotation on the server.
The current Annotation Web services API does not address every issue involved in annotations. This section covers some examples on unaddressed annotation issues.
The design goals of the Annotation Web services API favor a world in which data objects are unchanging. In particular, the goal of identifying a data source solely by its contents makes support for annotations on changing data sources challenging. The Annotation Web services API does not provide any support for changing data; implementations are free to add such support.
As referenced in the two usage examples of the API, many common procedures require the same API calls, often with the same parameters. Under a light load, this would not be a problem, but with many users using a single annotation server, duplicate calls seem an unnecessary burden. Because many of the objects in the annotation data model would likely be unchanging after an initial configuration deployment, an annotation client and server could implement effective caching policies that eliminate much of the repetition.
The Annotation Web services API as presented in this article does not provide any way to retrieve annotations based upon the content of the data (the instance document). Implementations would likely provide a mechanism for performing arbitrarily complex data-mining operations on annotation data. A standard API method for generic queries against annotation data has been proposed but at the time of this writing has not yet been finalized.
To conclude this introduction to the Annotation Web services API, let's return to the original design goals and examine how the data model and API methods fulfill these goals. The first goal was that the API should allow the annotation of arbitrary digital data. The only requirement the API placed on the digital data being annotated states that it must be possible to generate a data source identifier from the data source’s contents. Hash values satisfy this requirement easily. Many data sources also have existing identifiers that fulfill the API's requirements on data source identifiers, such as document management system identifiers, that implementations could use instead of hash values.
Data source identifiers are used to satisfy the second design goal: that the annotations be stored separately from the data being annotated and that the data sources be independent of location. The data source descriptor abstraction is kept separate from the instance document throughout the API to achieve this goal.
The next goal was to allow structured annotations. This goal is inherent in the design of this system, as every annotation manipulated with this API has a corresponding structure. The structures have a high degree of expressibility. Furthermore, field-level access control can adjust a structure based on the roles of the current user.
The inclusion of both field-level and instance-level access control lists satisfies the requirement for a thorough access-control mechanism. The twin methods QueryLocations() and QueryAnnotationIds() allow for data sources to be located from an annotation and vice versa. Finally, the inclusion of field facets, extensible instance action permissions, configurable relations between data source types, subtypes, structures, and arbitrary login properties all allow implementations substantial flexibility and room for enhancements to the features of the base API.
| Name | Size | Download method |
|---|---|---|
| ws-annotationsapi.zip | HTTP |
Information about download methods
- Download the WSDL and semantic documentation for the Annotation Web services API. When you unpack the documentation archive, you should have a folder named
AnnotationWSAPIDocs. To read the semantic documentation, start withAnnotationWSAPIDocs/apiWebServicesAPI.htm. The WSDL files needed are contained in the directoryAnnotationWSAPIDocs/wsdl. - Check out the W3C's overview of collaboration as it affects the World Wide Web. This includes some alternate views on Web annotation and collaboration.
- Check out the IBM InsightLink. This product contains an implementation of the Annotation Web services API.
Lee Feigenbaum is a software engineer in the IBM Advanced Internet Technology group. He currently works on the IBM Life Science InsightLink product, an implementation of the API presented in this article. Lee is a 2001 graduate of Harvard University's computer science program, and can be contacted at feigenbl@us.ibm.com.





