How to: Create an Adapter

This topic shows you how to create an adapter you can use to add a new field to a dimension in the warehouse.

In the following example, the user adds a new field called Policy Override to the Changeset dimension. A policy override happens whenever a user overrides a version control policy. At this point, the user enters a description of why he or she is overriding the policy. This example shows how to take the policy override description and put it into the Policy Override field for the changeset.

A warehouse adapter must implement the four methods in the IWarehouseAdapter interface. See Implementing an Adapter for more information.

Building the Adapter

  1. Create a new C# Class Library project in Visual Studio.

  2. Copy the code in this topic into the C# source file in the project.

  3. Create references to the following assemblies used by the adapter: Microsoft.TeamFoundation.dll, Microsoft.TeamFoundation.Client.dll, Microsoft.TeamFoundation.Common.dll, Microsoft.TeamFoundation.VersionControl.Client.dll, andMicrosoft.TeamFoundation.Warehouse.dll, and System.Web.

  4. Build the adapter as a DLL.

  5. Copy the build DLL into the warehouse plugins folder on the application tier.

    In most cases will be C:\Program Files\Microsoft Visual Studio 2005 Team Foundation Server\Web Services\Warehouse\bin\Plugins.

  6. Reset IIS.

  7. On the application tier, navigate to https://localhost:8080/Warehouse/v1.0/warehousecontroller.asmx?op=Run and click Invoke.

  8. On the application tier, navigate to https://localhost:8080/Warehouse/v1.0/warehousecontroller.asmx?op=GetWarehouseStatus and click Invoke. Continue doing this until the status is returned as Idle.In the application event log, an exception will be thrown by the Version Control Adapter. This is expected.

  9. Reset IIS.

Example

The first four methods after the constructor in this example implement the methods specified in the IWarehouseAdapter interface.

The Initialize method creates objects that communicate with the operational store and the warehouse.

The MakeSchemaChanges method creates a new dimension attribute in the warehouse. This attribute contains the policy override description.

The MakeDataChanges method is called each time you update the warehouse. In this adapter, the method checks all changesets made since the last warehouse update. If a changeset contains a description of the policy override, it calls the SavePolicyOverrideCommentDimAttribute method, which saves the description in the warehouse.

Call the RequestStop method when you want to stop the adapter.

The SavePolicyOverrideCommentDimAttribute method is a private method that does the actual updating of the warehouse. It is called for each changeset with a policy override description.

The LastChangesetProcessed field simply holds the state of the adapter between updates. Thus, it updates the warehouse only for new changesets.

using System;
using Microsoft.TeamFoundation;
using Microsoft.TeamFoundation.Adapter;
using Microsoft.TeamFoundation.Warehouse;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.VersionControl.Client;

namespace Microsoft.TeamFoundation.Samples.Reporting
{
  public sealed class PolicyOverrideAdapter : IWarehouseAdapter
  {
    private bool m_stopRequested = false;
    private IDataStore m_dataStore;
    private VersionControlServer m_vcServer;

    public PolicyOverrideAdapter()
    {
    }

    public void Initialize(IDataStore ds)
    {
      m_dataStore = ds;
      if (m_dataStore == null)
      {
        throw new Exception("Null data store.");
      }

      String url = Microsoft.TeamFoundation.Server.TeamFoundationApplication.TfsNameUrl;

      TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer(url);
      if (tfs == null)
      {
        throw new Exception("TF Server instance not obtained for TFS url: " + url);
      }

      m_vcServer = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
      if (m_vcServer == null)
      {
        throw new Exception("Version Control server instance not obtained for TFS url: " + url);
      }
    }

    // save schema changes to the data warehouse
    public SchemaChangesResult MakeSchemaChanges()
    {
      SchemaChangesResult result = SchemaChangesResult.NoChanges;

      // Check if the dimension attribute exists.
      WarehouseConfig config = m_dataStore.GetWarehouseConfig();
      Dimension changesetDim = config.GetDimension("Changeset");

      // Check if the Changeset dimension exists.
      // This should not happen, but another adapter may for some reason have deleted the Changeset dimension.
      if (changesetDim == null)
      {
        throw new Exception("Changeset dimension does not exist!");
      }

      // Get dimension attribute.
      Field dimensionAttribute = changesetDim.GetField("Policy Override Comment");

      // Add attribute to schema.
      if (dimensionAttribute == null)
      {
        // Check if adapter is requested to stop
        if (m_stopRequested)
        {
          return SchemaChangesResult.StopRequested;
        }

        // Transactions are recommended when writing to the warehouse.
        m_dataStore.BeginTransaction();

        try
        {
          // Create the Policy Override Comment dimension attribute 
          Field field = new Field();
          field.Name = "Policy Override Comment";
          field.Type = "NVARCHAR";
          field.Length = 128;

          // Add this attribute to Changeset dimension
          m_dataStore.AddDimensionField("Changeset", field);
          m_dataStore.CommitTransaction();
        }
        catch
        {
          m_dataStore.RollbackTransaction();
          throw;
        }

        result = SchemaChangesResult.ChangesComplete;
      }

      return result;
    }

    // save any new data changes in the operational store to the data warehouse
    public DataChangesResult MakeDataChanges()
    {
      DataChangesResult result = DataChangesResult.NoChanges;
      int lastChangesetID = m_vcServer.GetLatestChangesetId();
      int startChangesetID = LastChangesetProcessed + 1;
      // Start looping through changesets.
      for (int changesetID = startChangesetID; changesetID <= lastChangesetID; changesetID+)
      {
        // Check if adapter is requested to stop.
        if (m_stopRequested)
        {
          return DataChangesResult.StopRequested;
        }

        Changeset c = m_vcServer.GetChangeset(changesetID);
        PolicyFailureInfo[] failureInfoArray = c.PolicyOverride.PolicyFailures;

        // Save override comment.
        if (failureInfoArray.Length > 0)
        {
          SavePolicyOverrideCommentDimAttribute(c);
          result = DataChangesResult.ChangesComplete;
        }

        // Update last changeset processed.
        LastChangesetProcessed = changesetID;
      }
      m_dataStore.LogEvent(AdapterEventLevel.Informational, "Updated warehouse");
      return result;
    }

    public void RequestStop()
    {
      m_stopRequested = true;
    }

    // Creates and saves a dimension member for Changeset.
    private void SavePolicyOverrideCommentDimAttribute(Changeset c)
    {
      // CreateDimensionMember gets a DimensionMember to populate.
      // Once you fill in the fields for this member, you can save it to the warehouse.
      DimensionMember dimMember = m_dataStore.CreateDimensionMember("Changeset");

      // Whenever creating a dimension member, the key field needs to have a value.
      // For changeset, the key field is "Changeset ID".
      // The VC adapter will fill in the rest of the fields for this entry (such as [Changeset]).
      // We only specify the [Policy Override Comment]
      dimMember["Changeset ID"] = c.ChangesetId;

      String comment = c.PolicyOverride.Comment;
      // In case the comment is null or empty, we'll supply a default entry.
      // We should not enter this if clause.
      if (String.IsNullOrEmpty(comment))
      {
        comment = "Policy Failure!";
      }
      else if (comment.Length > 128)
      {
        comment = comment.Substring(0, 125) + "...";
      }

      dimMember["Policy Override Comment"] = comment;

      m_dataStore.BeginTransaction();

      try
      {
        m_dataStore.SaveDimensionMember(dimMember);
        m_dataStore.CommitTransaction();
      }
      catch
      {
        m_dataStore.RollbackTransaction();
        throw;
      }
    }

    // Last changeset that was populated.
    private int LastChangesetProcessed
    {
      get
      {
        String lastChangesetProcessedStr = m_dataStore.GetProperty("PolicyOverride LastChangesetProcessed");

        int lastChangesetProcessed = 0;
        if (!String.IsNullOrEmpty(lastChangesetProcessedStr))
        {
          lastChangesetProcessed = Int32.Parse(lastChangesetProcessedStr);
        }

        return lastChangesetProcessed;
      }
      set
      {
        m_dataStore.BeginTransaction();

        try
        {
          m_dataStore.SetProperty("PolicyOverride LastChangesetProcessed", value.ToString());
          m_dataStore.CommitTransaction();
        }
        catch
        {
          m_dataStore.RollbackTransaction();
          throw;
        }
      }
    }
  }
}

See Also

Tasks

How to: Create an Adapter

Concepts

Data Warehouse Organization

Implementing an Adapter

Data Warehouse Extensibility

Reference

IWarehouseAdapter

Initialize

MakeDataChanges

MakeSchemaChanges

RequestStop

Other Resources

Team Foundation Server Data Warehouse

Team Foundation Server SDK