Compartilhar via


IPolicyFeature.ProcessListItem Method

Returns a Boolean value that specifies whether Microsoft SharePoint Server 2010 continues to process the remaining list items.

Namespace:  Microsoft.Office.RecordsManagement.InformationPolicy
Assembly:  Microsoft.Office.Policy (in Microsoft.Office.Policy.dll)

Syntax

'Declaration
Function ProcessListItem ( _
    site As SPSite, _
    policyItem As PolicyItem, _
    listItem As SPListItem _
) As Boolean
'Usage
Dim instance As IPolicyFeature
Dim site As SPSite
Dim policyItem As PolicyItem
Dim listItem As SPListItem
Dim returnValue As Boolean

returnValue = instance.ProcessListItem(site, _
    policyItem, listItem)
bool ProcessListItem(
    SPSite site,
    PolicyItem policyItem,
    SPListItem listItem
)

Parameters

Return Value

Type: System.Boolean
If a policy feature returns true, SharePoint Server 2010 continues to process the remaining list items. If a policy feature returns false, SharePoint Server 2010 does not process the remaining items.

Remarks

When a policy changes, SharePoint Server 2010 calls the ProcessListItem method for each list item that is affected by a policy change.

Policy changes include editing the policy currently assigned to the list, or assigning a different policy to the list.

If a policy feature returns false, SharePoint Server 2010 does not process the remaining items. This optimization prevents SharePoint Server 2010 from iterating through all the items on a list for policy features that are not involved with processing the item.

For more information, see IPolicyFeature Interface Overview (ECM) and Policy Feature Definitions in SharePoint Server 2010 (ECM).

The following example shows how to implement the IPolicyFeature interface. The sample shows how to get certificates for items at appropriate events, and expose links to the user interface for verifying those certificates.

For more information about the sample, see the DocIntegrityPolicyFeature code sample folder and EnterpriseContentManagementStarterKitSampleGuide document in the ECM Starter Kit code sample folders in the Microsoft Office SharePoint Server 2010 SDK download.

Examples

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Office.RecordsManagement.InformationPolicy;
using Microsoft.SharePoint;
using System.Xml;
using System.Security.Cryptography;

namespace Microsoft.Office.Samples.ECM.RecordsManagement
{
    // The Document Integrity policy feature: This class does 
    // the work of getting certificates for items 
    // at appropriate events, and exposes links 
    // to the user interface for verifying those certificates.
    public class DocumentIntegrityFeature : 
     Microsoft.Office.RecordsManagement.InformationPolicy.IPolicyFeature
    {
        #region Names of properties or fields created by this feature
        
        public static string sCertPropertyName = "IntegrityCertificate";
        public static string sCertValidateFieldName = "Integrity Certificate";
        
        #endregion

        #region Verify Certificate URL information
        public static string sVerifyPageUrl =
            "https://localhost:81/verifycertificate/verifycertificate.aspx";
        public static string sWebUrlParamName = "WebUrl";
        public static string sListIDParamName = "List";
        public static string sItemParamName = "Item";
        

        // The getVerifyUrl helper method constructs the URL 
        // used to verify the certificate for a list item, which 
        // will be stored as a URL column on the list item.
        public static string getVerifyUrl(SPListItem i)
        {
            StringBuilder s = new StringBuilder();
            s.Append(sVerifyPageUrl);
            s.Append("?");
            s.Append(sWebUrlParamName + "=" + i.ParentList.ParentWeb.Url + "&");
            s.Append(sListIDParamName + "=" + i.ParentList.ID.ToString() + "&");
            s.Append(sItemParamName + "=" + i.ID.ToString());
            return s.ToString();
        }
        #endregion

        // The OnCustomDataChange method is not used in this 
        // demonstration, but this method is used generally to update 
        // the policy feature state appropriately 
        // when the custom data for the policy feature changes. 
        // For example, if the policy feature provides a user interface 
        // or custom data for controlling when a policy item should get 
        // a certificate, the code to register or unregister
        // event receivers for those events 
        // would be included in this function. 
        public void OnCustomDataChange(PolicyItem policyItem, SPContentType ct)
        {         
        }

        // The OnGlobalCustomDataChange method is also not used in this 
        // demonstration, but this method is generally used to update 
        // the policy feature state appropriately when the 
        // Microsoft Office SharePoint Server 2007 
        // Central Administration settings for the policy feature 
        // change. For example, if the policy feature allows 
        // the central administrator to provide the key used 
        // to sign certificates, you can use this method to propagate 
        // that information into the appropriate locations 
        // or content types.
        public void OnGlobalCustomDataChange(PolicyFeature feature)
        {
        }
        
        // The ProcessListItem method is called by the policy 
        // framework on list items that were uploaded in a list before 
        // the policy is applied to the list; that is, the ones that 
        // might never be acted on by an event receiver.
        public bool ProcessListItem(SPSite site, PolicyItem policyItem, SPListItem listItem)
        {
            // Check if the item already has
            // an integrity certificate. 
            string sCert = (string)listItem.Properties[sCertPropertyName];
            if ((sCert == null) || (sCert == ""))
            {
                // If the call reaches here, then the item does not have 
                // a certificate yet, so create one for it. 
                IntegrityCertificateEvents.SetIntegrityCertificate(listItem);
            }
            return true;
        }

        // The ProcessListItemOnRemove method is also not used in this 
        // demonstration. The policy framework calls this method 
        // for list items that are no longer subjected 
        // to the policy. So if there is any item-level 
        // unregistration work you need to do, this is the place 
        // to do it.
        public bool ProcessListItemOnRemove(SPSite site, SPListItem listItem)
        {
            return true;
        }

        // The Register method is called on a content type when your 
        // policy is added to that content type. It is where you 
        // register event receivers, add fields to the content type, or 
        // do any other work on a list or content type for 
        // your feature.
        public void Register(SPContentType ct)
        {
            // Step 1: Add the "ItemAdded" and "ItemUpdated" 
            // event receivers to the content type.
            IntegrityCertificateEvents.AddEventReceiver(ct, IntegrityCertificateEvents.sEventHandlerName, "Microsoft.Office.Samples.ECM.RecordsManagement.IntegrityCertificateEvents", SPEventReceiverType.ItemAdded, 111);
            IntegrityCertificateEvents.AddEventReceiver(ct, IntegrityCertificateEvents.sEventHandlerName, "Microsoft.Office.Samples.ECM.RecordsManagement.IntegrityCertificateEvents", SPEventReceiverType.ItemUpdated, 111);

            // Step 2: Add the "Validate" link field to the 
            // content type. 
            // Get the appropriate field collection, depending on 
            // whether you are in a site or list content type. 
            SPFieldCollection fields = (ct.ParentList == null) ? ct.ParentWeb.Fields : ct.ParentList.Fields;
            SPField fldToAdd = null;
            try
            {
                // Check if the field already exists. 
                fldToAdd = fields[sCertValidateFieldName];
            }
            catch
            {
                // If the field doesn't exist, then create it, 
                // and prevent the user from editing it.
                string sInternalFldName = fields.Add(sCertValidateFieldName, SPFieldType.URL, false);
                fields[sCertValidateFieldName].ShowInEditForm = false;
                fields[sCertValidateFieldName].ShowInNewForm = false;
                fields[sCertValidateFieldName].ShowInDisplayForm = true;
                fields[sCertValidateFieldName].Update();

                // Add to the content type.
                SPFieldLink verifyFld = new SPFieldLink(fields[sCertValidateFieldName]);
                ct.FieldLinks.Add(verifyFld);
                ct.Update();

                // If it is a list content type, and the field is not
                // the default list view, then add it.
                if ((ct.ParentList != null) && ((ct.ParentList.DefaultView.ViewFields.Exists(sCertValidateFieldName) == false)))
                {
                    SPView listView = ct.ParentList.DefaultView;
                    listView.ViewFields.Add(sCertValidateFieldName);
                    listView.Update();
                } //if
                          
            } //catch

            // Make sure the Web site is not automatically 
            // parsing files because this will invalidate certificates
            // quickly.

            SPWeb w = ct.ParentWeb;
            if (w.ParserEnabled == true)
            {
                w.ParserEnabled = false;
                w.Update();
            }
        }

        // The UnRegister method is called on a content type when 
        // your policy is removed from the content type. Here is where 
        // you should undo anything you did 
        // when you called the Register method
        // that should no longer be applied.
        public void UnRegister(SPContentType ct)
        {
            // Remove the event receivers so that the existing 
            // certifcates can still be verified, but so that the new items
            // do not get certificates. 
            IntegrityCertificateEvents.RemoveEventReceiver(ct, IntegrityCertificateEvents.sEventHandlerName, SPEventReceiverType.ItemAdded);
            IntegrityCertificateEvents.RemoveEventReceiver(ct, IntegrityCertificateEvents.sEventHandlerName, SPEventReceiverType.ItemUpdated);
        }
    }

    public class IntegrityCertificateEvents : SPItemEventReceiver
    {
        // The name of your event receiver. 
        // Find your event receiver in the set of 
        // event receivers registered for any event.
        public static string sEventHandlerName = "Integrity Certificate Policy Feature";

        public override void ItemAdded(SPItemEventProperties properties)
        {
            DisableEventFiring();
            base.ItemAdded(properties);
            SPListItem li = properties.ListItem;
            li[DocumentIntegrityFeature.sCertValidateFieldName] = DocumentIntegrityFeature.getVerifyUrl(li) + ", Verify...";
            li.Update();
            SetIntegrityCertificate(li);
        }

        public override void ItemUpdated(SPItemEventProperties properties)
        {
            DisableEventFiring();
            SPListItem li = properties.ListItem;
            // Check if the certificate has been generated 
            // by checking if the link has been created.
            if ((li[DocumentIntegrityFeature.sCertValidateFieldName] == null) || ( (string) li[DocumentIntegrityFeature.sCertValidateFieldName] == ""))
            {
                // Set the link and certificate for the 
                // item.
                li[DocumentIntegrityFeature.sCertValidateFieldName] = DocumentIntegrityFeature.getVerifyUrl(li) + ", Verify...";
                li.Update();
                SetIntegrityCertificate(li);
            }
        }
        
        #region Helper methods for adding event receivers
        internal static void AddEventReceiver(SPContentType ct, string name, string className, SPEventReceiverType type, int sequenceNumber)
        {
           if (ct.ParentList != null)
           {
               AddEventReceiver(ct.ParentList, name, className, type, sequenceNumber);
               return;
           }
           try
           {
               System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly();
               SPEventReceiverDefinition sperd = ct.EventReceivers.Add();
               sperd.Name = name;
               sperd.Type = type;
               sperd.SequenceNumber = sequenceNumber;
               sperd.Assembly = a.FullName;
               sperd.Class = className;
               sperd.Update();
           }
           catch (System.ArgumentException)
           {
               // This means the handler already exists.
           }
       }

        internal static void RemoveEventReceiver(SPContentType ct, string name, SPEventReceiverType type)
       {
           if (ct.ParentList != null)
           {
               RemoveEventReceiver(ct.ParentList, name, type);
               return;
           }

           SPEventReceiverDefinitionCollection sperdcol = ct.EventReceivers;
           for (int i = 0; i < sperdcol.Count; ++i)
           {
               SPEventReceiverDefinition sperd = sperdcol[i];
               if (sperd.Name == name && sperd.Type == type)
               {
                   sperd.Delete();
               }
           }
       }
       
        internal static void AddEventReceiver(SPList list, string name, string className, SPEventReceiverType type, int sequenceNumber)
       {
           try
           {
               System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly();
               SPEventReceiverDefinition sperd = list.EventReceivers.Add();
               sperd.Name = name;
               sperd.Type = type;
               sperd.SequenceNumber = sequenceNumber;
               sperd.Assembly = a.FullName;
               sperd.Class = className;
               sperd.Update();
           }
           catch (System.ArgumentException)
           {
               // This means the handler already exists.
           }
       }
    
        internal static void RemoveEventReceiver(SPList list, string name, SPEventReceiverType type)
       {
           SPEventReceiverDefinition sperd = null;
           SPEventReceiverDefinitionCollection sperdcol = list.EventReceivers;
           bool fFound = false;

           for (int i = 0; i < sperdcol.Count; ++i)
           {
               sperd = sperdcol[i];
               if (sperd.Name == name && sperd.Type == type)
               {
                   fFound = true;
                   break;
               }
           }

           if (fFound)
               sperd.Delete();
       }
        #endregion

        // Use the SetIntegrityCertificate method to obtain an 
        // integrity certificate for a list item (if it is a document), 
        // and store it as a property on the item.
        public static void SetIntegrityCertificate(SPListItem li)
        {
            try
            {
                byte[] b = li.File.OpenBinary();
                IntegrityCertificate ic = new IntegrityCertificate(b);
                string sCert = ic.ToString();
                li.Properties.Add(DocumentIntegrityFeature.sCertPropertyName, sCert);
                li.Update();
            }
            catch 
            {
                // Does nothing because this is a demonstration. 
            }    
        }
       
    }

    // The IntegrityCertificate class generates and 
    // verifies the integrity of the certificates for those files. 
    public class IntegrityCertificate
    {
        // The time this certificate was created.
        private DateTime dtGenerated;
        
        // The hash value of the item for which 
        // this certificate was created.
        private string sItemHash;

        #region Accessors
        // Public accessor for getting the date that the source event 
        // was generated.
        public  
        {
            get
            {
                return dtGenerated;
            }
        }

        // Public accessor for getting the item's hash value.
        public string Hash
        {
            get
            {
                return sItemHash;
            }
        }
        #endregion

        // Constructor 1: Takes a byte[], and creates 
        // a new certificate for that byte array. It is used to 
        // get a new certificate for a file, which will be stored 
        // as a serialized string. 
        public IntegrityCertificate(byte[] file)
        {
            this.dtGenerated = DateTime.Now;
            this.sItemHash = ComputeHash(file);
        }

        // Constructor 2: Takes a serialized certificate, and creates 
        // an instance of the class with the data in that certificate. 
        // It is used to verify that a certificate stored with a file 
        // still matches the file. 
        public IntegrityCertificate(string sCert)
        {
            // Step 1: Construct the certificate object 
            // using the string.
            XmlDocument xd = new XmlDocument();
            xd.LoadXml(sCert);

            XmlNode xn = xd.DocumentElement.SelectSingleNode("/Certificate/Hash");
            sItemHash = xn.FirstChild.Value;

            xn = xd.DocumentElement.SelectSingleNode("/Certificate/DateGenerated");
            dtGenerated = DateTime.Parse(xn.FirstChild.Value);
        }

        // The Verify method returns true if the file passed in 
        // matches the hash value stored in the certificate.
        public bool Verify(byte[] file)
        {
            string hash = ComputeHash(file);
            int nVerify = String.Compare(hash, this.sItemHash);

            if (nVerify == 0)
            {
                return true;
            }
            else
            {
                return false;
            }

        }

        // The ComputeHash private helper method is used to 
        // compute the hash value of a file.
        private string ComputeHash(byte[] file)
        {
            SHA512Managed SHAHash = new SHA512Managed();
            byte[] bHashValue = SHAHash.ComputeHash(file);
              = new UnicodeEncoding();
            return new string(ByteConverter.GetChars(bHashValue));
        }

        // The ToString method gets a string representation of the 
        // certificate, which can be persisted and later used 
        // to reconstruct the certificate.
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<Certificate>");
            sb.Append("<Hash>" + this.sItemHash + "</Hash>");
            sb.Append("<DateGenerated>" + this.dtGenerated.ToString() + "</DateGenerated>");
            sb.Append("</Certificate>");
            return sb.ToString();
        }
    }
}

See Also

Reference

IPolicyFeature Interface

IPolicyFeature Members

Microsoft.Office.RecordsManagement.InformationPolicy Namespace