Working with Annotation Objects

This topic provides the following code examples for annotations:

For an overview of annotations, see Annotation Concepts.

Annotating a Document

The following Java™ and C# examples show how to add an Annotation object to a document. After the Annotation is created, its DescriptiveText and ContentElements properties are set, the latter with the content of the annotation that is streamed from a File object.

In these examples, the Document object's createAnnotation method is used because it both creates the Annotation object and sets the object on a specified content element of the Document object. There is an alternative approach to using the Document object's createAnnotation method, but the alternative takes three lines of code to accomplish what createAnnotation does with one line of code. The alternative is to create the Annotation object with a Factory method, set the document on the Annotation object's AnnotatedObject property, and set the specific content element of the document on the Annotation object's AnnotatedContentElement property.

NOTE To set a specific document content element on an Annotation object's AnnotatedContentElement property, specify the ElementSequenceNumber property of the content element rather than the content element's indexed position in the ContentElementList object.

Java Example

// Create property filter for document's content elements, 
// which are needed to get element sequence numbers that identify elements.
PropertyFilter pf = new PropertyFilter();       
pf.addIncludeProperty(new FilterElement(null, null, null, PropertyNames.CONTENT_ELEMENTS, null));

// Get Document object
Document doc=Factory.Document.fetchInstance((os, new Id("{2A96C18B-CF94-4853-B105-3F0553A37D7F}"), pf);

// Get element sequence number of 2nd content element of the document.
// Set annotation on the content element identified by element sequence number. 
ContentElementList docContentList = doc.get_ContentElements();
Integer elementSequenceNumber = ((ContentElement) docContentList.get(1)).get_ElementSequenceNumber();

// Create the annotation from the document object,
// and set the annotation on the second content element of the document.
Annotation annObject = doc.createAnnotation(elementSequenceNumber.intValue(), 
                com.filenet.api.constants.ClassNames.ANNOTATION);

// Set annotation's DescriptiveText property
annObject.set_DescriptiveText("Annotation applied to the document's 2nd content element.");

// Create File object with annotation content
File annotationFile = new File("C:\\annotation.txt");

// Create ContentTransfer and ContentElementList objects for the annotation
ContentTransfer ctObject = Factory.ContentTransfer.createInstance();
ContentElementList annContentList = Factory.ContentTransfer.createList();
try
{
   FileInputStream fileIS = new FileInputStream(annotationFile.getAbsolutePath());
   ctObject.setCaptureSource(fileIS);
}
catch (Exception e)
{
   System.out.println(e.getMessage() );
}

// Add ContentTransfer object to list
annContentList.add(ctObject);
annObject.set_ContentElements(annContentList);

annObject.save(RefreshMode.REFRESH);

C# Example

// Create property filter for document's content elements, 
// which are needed to get element sequence numbers that identify elements.
PropertyFilter pf = new PropertyFilter();
pf.AddIncludeProperty(new FilterElement(null, null, null, PropertyNames.CONTENT_ELEMENTS, null));

// Get Document object
IDocument doc=Factory.Document.FetchInstance(os, new Id("{2A96C18B-CF94-4853-B105-3F0553A37D7F}"), pf);

// Get element sequence number of 2nd content element of the document.
// Set annotation on the content element identified by element sequence number. 
IContentElementList docContentList = doc.ContentElements;
int elementSequenceNumber = (int)((IContentElement)docContentList[1]).ElementSequenceNumber;

// Create the annotation from the document object,
// and set the annotation on the second content element of the document.
IAnnotation annObject = doc.CreateAnnotation(elementSequenceNumber, ClassNames.ANNOTATION);

// Set annotation's DescriptiveText property
annObject.DescriptiveText = "Annotation applied to the document's 2nd content element.";

// Create Stream object with annotation content
Stream fileStream = File.OpenRead(@"C:\\annotation3.txt");

// Create ContentTransfer and ContentElementList objects for the annotation
IContentTransfer ctObject = Factory.ContentTransfer.CreateInstance();
IContentElementList annContentList = Factory.ContentTransfer.CreateList();
ctObject.SetCaptureSource(fileStream);

// Add ContentTransfer object to list
annContentList.Add(ctObject);
annObject.ContentElements = annContentList;

annObject.Save(RefreshMode.REFRESH);

Annotating a Folder

The following Java and C# examples show how to add an Annotation object to a folder. Note that the procedure would be similar for a custom object.

Java Example

// Get Folder object
Folder folder=Factory.Folder.getInstance(os, "Folder", new Id("{1A570F51-63B9-4600-B717-03D44ECC54A1}") );

// Create Annotation object and set Folder as the annotated object.
Annotation annObject = Factory.Annotation.createInstance(os, "Annotation");
annObject.set_DescriptiveText("Annotation applied to folder via CE Java API");
annObject.set_AnnotatedObject(folder);

// Create File object with annotation content
File annotationFile = new File("C:\\annotation.txt");

// Create ContentTransfer and ContentElementList objects for the annotation
ContentTransfer ctObject = Factory.ContentTransfer.createInstance();
ContentElementList contentList = Factory.ContentTransfer.createList();
try 
{
   FileInputStream fileIS = new FileInputStream(annotationFile.getAbsolutePath());
   ctObject.setCaptureSource(fileIS);
}
catch (Exception e)
{
    System.out.println(e.getMessage() );
}

// Add ContentTransfer object to list
contentList.add(ctObject);
annObject.set_ContentElements(contentList);

annObject.save(RefreshMode.REFRESH);

C# Example

// Get Folder object
IFolder folder=Factory.Folder.GetInstance(os, "Folder", new Id("{1A570F51-63B9-4600-B717-03D44ECC54A1}") );

// Create Annotation object and set Folder as the annotated object.
IAnnotation annObject = Factory.Annotation.CreateInstance(os, "Annotation");
annObject.DescriptiveText = "Annotation applied to folder via CE .NET API";
annObject.AnnotatedObject = folder;

// Create Stream object with annotation content
Stream fileStream = File.OpenRead(@"C:\\annotation.txt");

// Create ContentTransfer and ContentElementList objects for the annotation
IContentTransfer ctObject = Factory.ContentTransfer.CreateInstance();
IContentElementList contentList = Factory.ContentTransfer.CreateList();
ctObject.SetCaptureSource(fileStream);

// Add ContentTransfer object to list
contentList.Add(ctObject);
annObject.ContentElements = contentList;

annObject.Save(RefreshMode.REFRESH);

Retrieving Annotations

The following Java and C# examples show how to retrieve the annotations applied to a Document object. The code gets the AnnotationSet from the Document and iterates the set, printing property values of each Annotation object in the set. Because an annotation can have more than one content element, the code also iterates the StringList object of the Annotation object's ContentElementsPresent property.

Java Example

// Create PropertyFilter for annotations
PropertyFilter pf = new PropertyFilter();
pf.addIncludeProperty(new FilterElement(null, null, null, "Annotations", null)); 

// Get document
Document doc=Factory.Document.fetchInstance(os, "{2A96C18B-CF94-4853-B105-3F0553A37D7F}", pf);

// Get AnnotationSet from document.
// Iterate AnnotationSet and print property values of each annotation.
AnnotationSet as = doc.get_Annotations();
Iterator iter = as.iterator();
while (iter.hasNext() )
{
   Annotation annObject = (Annotation)iter.next();
   System.out.println("Name: " + annObject.get_Name() + "\n" +
      "Description: " + annObject.get_DescriptiveText() + "\n" +
      "Document's content element that's annotated: " + annObject.get_AnnotatedContentElement() + "\n" +
      "Content size: " + annObject.get_ContentSize().toString() + "\n" +
      "Storage area: " + annObject.get_StorageArea().get_DisplayName() + "\n" +
      "No. of content elements in annotation: " + annObject.get_ContentElements().size()
   );
   // Print the MIME type of the annotation's content element.
   // Some annotations may have more than one content element.
   StringList sl = annObject.get_ContentElementsPresent();
   for(int i=0; i < sl.size(); i++ )
   {
      System.out.println("MIME type of annotation content element #" + (i+1) + ": " + 
          sl.get(i) );
   }
}

C# Example

// Create PropertyFilter for annotations
PropertyFilter pf = new PropertyFilter();
pf.AddIncludeProperty(new FilterElement(null, null, null, PropertyNames.ANNOTATIONS, null)); 

// Get document
IDocument doc=Factory.Document.FetchInstance(os, "{2A96C18B-CF94-4853-B105-3F0553A37D7F}", pf);

// Get IAnnotationSet from document.
// Iterate IAnnotationSet and print property values of each annotation.
IAnnotationSet annSet = doc.Annotations;
System.Collections.IEnumerator annSetIter = annSet.GetEnumerator();
while (annSetIter.MoveNext())
{
   IAnnotation annObject = (IAnnotation)annSetIter.Current; 
   System.Console.WriteLine("Name: " + annObject.Name + "\n" +
      "Description: " + annObject.DescriptiveText + "\n" +
      "Document's content element that's annotated: " + annObject.AnnotatedContentElement + "\n" +
      "Content size: " + annObject.ContentSize.ToString() + "\n" +
      "Storage area: " + annObject.StorageArea.DisplayName + "\n" +
      "No. of content elements in annotation: " + annObject.ContentElements.Count
   );
   // Print the MIME type of the annotation's content element.
   // Some annotations may have more than one content element.
   IStringList sl = annObject.ContentElementsPresent;
   for(int i=0; i < sl.Count; i++ )
   {
      System.Console.WriteLine("MIME type of annotation content element #" + (i+1) + ": " + 
          sl[i] );
   }
}

Moving Content to a Different Storage Area

The following Java and C# examples show how to move the content of an Annotation object to a different storage area, in this case an area represented by a FileStorageArea object.

Java Example

// Get the storage area where you want to move the annotation content
FileStorageArea fsa = Factory.FileStorageArea.fetchInstance(os, new Id("{AF44998A-9779-464E-AC23-E94F6E14D79B}"), null);

// Get the Annotation object whose content you want to move
Annotation annObject = Factory.Annotation.getInstance(os, "Annotation", new Id("{CD467BBD-5CC1-44A4-9842-13368996BDD6}") );

// Move the content and save the Annotation object
annObject.moveContent(fsa);
annObject.save(RefreshMode.REFRESH);

C# Example

// Get the storage area where you want to move the annotation content
IFileStorageArea fsa = Factory.FileStorageArea.FetchInstance(os, new Id("{AF44998A-9779-464E-AC23-E94F6E14D79B}"), null);

// Get the IAnnotation object whose content you want to move
IAnnotation annObject = Factory.Annotation.GetInstance(os, "Annotation", new Id("{CD467BBD-5CC1-44A4-9842-13368996BDD6}") );

// Move the content and save the IAnnotation object
annObject.MoveContent(fsa);
annObject.Save(RefreshMode.REFRESH);

Creating an Annotation Subclass

The following Java and C# examples show how to create a subclass from the base, system-provided Annotation class. In the examples, the subclass is named "Proposal" because annotations of this class are intended for a proposal document for which comments have been solicited. Note that a custom property of type PropertyTemplateBoolean is added to the subclass. The property, called "Change Type", is defined as required, and its purpose is to indicate to the proposal writer whether the annotation is merely a suggestion or a required change. Therefore, when a reviewer sets an annotation on the proposal document, the reviewer will have to set the "Change Type" property.

The new annotation subclass can be used to create new annotation instances, as shown in Creating a New Subclass Instance. The new subclass can also be applied to existing instances that are defined by different annotation classes, as shown in Changing an Annotation's Class.

Java Example

// Fetch selected class definition from the server
ClassDefinition parentClassDef = Factory.ClassDefinition.fetchInstance(os, "Annotation", null);

String subclassName = "Proposal";
      
// Create subclass of the Annotation class
ClassDefinition newClassDef = parentClassDef.createSubclass();
        
// Set required properties to localized string
LocalizedString locStr1 = getLocalizedString(subclassName, os.get_LocaleName() );
newClassDef.set_DisplayNames(Factory.LocalizedString.createList() );
newClassDef.get_DisplayNames().add(locStr1);
    
LocalizedString locStr2 = getLocalizedString("For annotations specific to Proposal document", 
       os.get_LocaleName() );
newClassDef.set_DescriptiveTexts(Factory.LocalizedString.createList() );
newClassDef.get_DescriptiveTexts().add(locStr2);
        
// Create new PropertyTemplate for boolean property with required value
PropertyTemplateBoolean newPropTemplate = Factory.PropertyTemplateBoolean.createInstance(os);
newPropTemplate.set_Cardinality (Cardinality.SINGLE);
newPropTemplate.set_IsValueRequired(Boolean.TRUE);

// Set required properties to localized string
LocalizedString locStr3 = getLocalizedString("Change Type", os.get_LocaleName() );
newPropTemplate.set_DisplayNames (Factory.LocalizedString.createList() );
newPropTemplate.get_DisplayNames().add(locStr3);
        
LocalizedString locStr4 = getLocalizedString("Indicates suggested or required change to proposal",
       os.get_LocaleName() );
newPropTemplate.set_DescriptiveTexts(Factory.LocalizedString.createList() );
newPropTemplate.get_DescriptiveTexts().add(locStr4);
        
// Save property template to the server
newPropTemplate.save(RefreshMode.REFRESH);

// Create property definition from property template
PropertyDefinitionBoolean newPropDef = (PropertyDefinitionBoolean)newPropTemplate.createClassProperty();
        
// Get PropertyDefinitions property from the property cache
PropertyDefinitionList propDefs = newClassDef.get_PropertyDefinitions(); 

// Add new property definition to class definition
propDefs.add(newPropDef);

newClassDef.save(RefreshMode.REFRESH); 

private LocalizedString getLocalizedString(String text, String locale)
{
   LocalizedString locStr = Factory.LocalizedString.createInstance ();
   locStr.set_LocalizedText(text);
   locStr.set_LocaleName (locale);
   return locStr;
}

C# Example

// Fetch selected class definition from the server
IClassDefinition parentClassDef = Factory.ClassDefinition.FetchInstance(os, "Annotation", null);

String subclassName = "Proposal";

// Create subclass of the Annotation class
IClassDefinition newClassDef = parentClassDef.CreateSubclass();

// Set required properties to localized string
ILocalizedString locStr1 = GetLocalizedString(subclassName, os.LocaleName);
newClassDef.DisplayNames = Factory.LocalizedString.CreateList();
newClassDef.DisplayNames.Add(locStr1);

ILocalizedString locStr2 = GetLocalizedString("For annotations specific to Proposal document",
       os.LocaleName);
newClassDef.DescriptiveTexts = Factory.LocalizedString.CreateList();
newClassDef.DescriptiveTexts.Add(locStr2);

// Create new PropertyTemplate for boolean property with required value
IPropertyTemplateBoolean newPropTemplate = Factory.PropertyTemplateBoolean.CreateInstance(os);
newPropTemplate.Cardinality = Cardinality.SINGLE;
newPropTemplate.IsValueRequired = true;

// Set required properties to localized string
ILocalizedString locStr3 = GetLocalizedString("Change Type", os.LocaleName);
newPropTemplate.DisplayNames = Factory.LocalizedString.CreateList();
newPropTemplate.DisplayNames.Add(locStr3);

ILocalizedString locStr4 = GetLocalizedString("Indicates suggested or required change to proposal",
       os.LocaleName);
newPropTemplate.DescriptiveTexts = Factory.LocalizedString.CreateList();
newPropTemplate.DescriptiveTexts.Add(locStr4);

// Save property template to the server
newPropTemplate.Save(RefreshMode.REFRESH);

// Create property definition from property template
IPropertyDefinitionBoolean newPropDef = (IPropertyDefinitionBoolean)newPropTemplate.CreateClassProperty();

// Get PropertyDefinitions property from the property cache
IPropertyDefinitionList propDefs = newClassDef.PropertyDefinitions;

// Add new property definition to class definition
propDefs.Add(newPropDef);

newClassDef.Save(RefreshMode.REFRESH);

private ILocalizedString GetLocalizedString(String text, String locale)
{
   ILocalizedString locStr = Factory.LocalizedString.CreateInstance();
   locStr.LocalizedText = text;
   locStr.LocaleName = locale;
   return locStr;
}

Creating a New Subclass Instance

As demonstrated in Creating an Annotation Subclass above, a subclass called "Proposal" was created. The following Java and C# examples show how to create a new annotation using the "Proposal" subclass, and to set it on a document. Note that the "Proposal" subclass includes a custom property that is required to be set on a new annotation; if it is not set, an exception will be thrown when an attempt is made to save the new annotation.

Java Example

// Get proposal document
Document doc=Factory.Document.getInstance(os, "Document", new Id("{512D355A-8DBF-40D4-9485-683CBDF3C860}") );

// Create new annotation of type Proposal, and set it on the proposal document
Annotation annObject = Factory.Annotation.createInstance(os, "Proposal");
annObject.set_DescriptiveText("Annotation of class type Proposal");
annObject.set_AnnotatedObject(doc);

// Get Proposal class in order to identify the required custom property
ClassDefinition newClass = Factory.ClassDefinition.fetchInstance(os, "Proposal", null);
PropertyDefinitionList pdl = newClass.get_PropertyDefinitions();
Iterator iter = pdl.iterator();
String custProperty=null;
while (iter.hasNext() )
{
    PropertyDefinition pd = (PropertyDefinition)iter.next();
    if (!pd.get_IsSystemOwned().booleanValue())
    {
        System.out.println("Custom property: " + pd.get_DisplayName() );
        System.out.println("Value required?: " + pd.get_IsValueRequired() );
        custProperty = pd.get_SymbolicName();
    }
}

// Set required custom property on new annotation
com.filenet.api.property.Properties props = annObject.getProperties();
props.putValue(custProperty, true);
annObject.save(RefreshMode.REFRESH);

C# Example

// Get proposal document
IDocument doc=Factory.Document.GetInstance(os, "Document", new Id("{512D355A-8DBF-40D4-9485-683CBDF3C860}") );

// Create new annotation of type Proposal, and set it on the proposal document
IAnnotation annObject = Factory.Annotation.CreateInstance(os, "Proposal");
annObject.DescriptiveText = "Annotation of class type Proposal";
annObject.AnnotatedObject = doc;

// Get Proposal class in order to identify the required custom property
IClassDefinition newClass = Factory.ClassDefinition.FetchInstance(os, "Proposal", null);
IPropertyDefinitionList pdl = newClass.PropertyDefinitions;
System.Collections.IEnumerator Iter = pdl.GetEnumerator();
String custProperty=null;
while (Iter.MoveNext())
{
   IPropertyDefinition pd = (IPropertyDefinition)Iter.Current;
   if (!(bool)pd.IsSystemOwned)
   {
      System.Console.WriteLine("Custom property: " + pd.DisplayName);
      System.Console.WriteLine("Value required?: " + pd.IsValueRequired);
      custProperty = pd.SymbolicName;
   }
}

// Set required custom property on new annotation
annObject.Properties[custProperty] = true;
annObject.Save(RefreshMode.REFRESH);

Changing an Annotation's Class

As demonstrated in Creating an Annotation Subclass above, a subclass called "Proposal" was created. The following Java and C# examples show how to set this new annotation subclass on an existing annotation instance by changing the annotation's class. Note that the property settings of the existing annotation instance will be unaffected by the new subclass. In addition, the required custom property of the "Proposal" subclass, called "Change Type", will not have to be set on the existing instance.

Java Example

// Get annotation whose class you want to change
Annotation annObject = Factory.Annotation.getInstance(os, "Annotation", new Id("{A59A7728-1804-499B-B564-7F6C5443174F}") );

// Change the class by specifying the ID of the new "Proposal" subclass,
// and save the annotation.
annObject.changeClass("{0E628F78-AF62-49D9-88CB-18B6F4E89210}");
annObject.save(RefreshMode.REFRESH);

C# Example

// Get annotation whose class you want to change
IAnnotation annObject = Factory.Annotation.GetInstance(os, "Annotation", new Id("{A59A7728-1804-499B-B564-7F6C5443174F}"));

// Change the class by specifying the ID of the new "Proposal" subclass,
// and save the annotation.
annObject.ChangeClass("{0E628F78-AF62-49D9-88CB-18B6F4E89210}");
annObject.Save(RefreshMode.REFRESH);