2009年2月17日火曜日

MVRouterアーキテクチャ



引き続きILM(というかMIIS)の話題です。
なぜ今さら、という話もあるんですがILM"2"も結局はHybridな構造なので、レガシーな作り込みはおそらくなくならないだろうな~、と思っているからです。
ライセンス的にもILM"2"の画面系を使わなければCAL不要?みたいな話もありそうなので、管理者だけがWSS上でアカウントを管理して実ユーザにセルフサービスはさせないという使い方も実際はあり得そうですし。

さて、MIIS/ILMの最大の欠点は何か?と言われたら、Metaverseのrules extensionが実質ひとつのDLLに閉じられてしまっていて、分散開発やメンテナンスがとってもしにくい、という点があげられると思います。
MIISのDeveloperリファレンスにも載っているので、実際に商用環境で使っている方はこの方法を使っているのかな?とは思いますが、その名も「MVRouter」です。

やっていることは単純で、親DLLから各ターゲット用に用意したextension用DLLを呼び出しているだけですが、これでずいぶんメンテナンスは楽になるのかと思います。
















具体的には下記のようなコードを書きます。

■親DLL(MVExtention.dll)

Imports Microsoft.MetadirectoryServices
Imports System.IO
Imports System.Reflection

Public Class MVExtensionObject
  Implements IMVSynchronization

  ' 変数定義
  Dim arrMVDlls() As IMVSynchronization

  Public Sub Initialize() Implements IMvSynchronization.Initialize
    ' MVExtensionファイル名の取得の読み込み
    Dim arrDllNames() As String = Directory.GetFiles(Utils.ExtensionsDirectory, "MV_Ext_" & "*.dll")
    Dim numDlls As Integer = arrDllNames.Length - 1
    ReDim arrMVDlls(numDlls)
    Dim iCnt As Integer
    Dim strFileName As String
    Dim Assem As [Assembly]
    Dim type, types() As Type
    Dim objLoaded As Object
    Dim isLoaded As Boolean

    ' MVExtentionライブラリのロード
    For iCnt = 0 To numDlls
      strFileName = arrDllNames(iCnt)
      Assem = [Assembly].LoadFrom(strFileName)
      types = Assem.GetExportedTypes()

      ' MVExtentionライブラリであることを確認
      isLoaded = False
      For Each type In types
        If (Not (type.GetInterface("Microsoft.MetadirectoryServices.IMVSynchronization") Is Nothing)) Then
          ' オブジェクトインスタンスの生成
          objLoaded = Assem.CreateInstance(type.FullName)
          isLoaded = True
          Exit For
        End If
      Next

      If isLoaded = True Then
        ' ロードしたライブラリを変数へ代入
        arrMVDlls(iCnt) = objLoaded
        ' ライブラリの初期化
        arrMVDlls(iCnt).Initialize()
      Else
        ' ロード対象ライブラリが存在しなかったら例外処理
        Throw New UnexpectedDataException("MVExtensionライブラリが見つかりません")
      End If

    Next
  End Sub

  Public Sub Terminate() Implements IMvSynchronization.Terminate
    Dim objDll As IMVSynchronization
    ' ロードされたライブラリの終了処理
    For Each objDll In arrMVDlls
      objDll.Terminate()
    Next
  End Sub

  Public Sub Provision(ByVal mventry As MVEntry) Implements IMVSynchronization.Provision
    Dim objDll As IMVSynchronization
    ' 各ライブラリのProvisioning実行
    For Each objDll In arrMVDlls
      objDll.Provision(mventry)
    Next
  End Sub

  Public Function ShouldDeleteFromMV(ByVal csentry As CSEntry, ByVal mventry As MVEntry) As Boolean Implements IMVSynchronization.ShouldDeleteFromMV
    Dim objDll As IMVSynchronization
    Dim shouldDelete As Boolean = False

    ' 各ライブラリのShouldDeleteFromMV実行
    For Each objDll In arrMVDlls
      If objDll.ShouldDeleteFromMV(csentry, mventry) Then
        shouldDelete = True
        Exit For
      End If
    Next

    ShouldDeleteFromMV = shouldDelete
  End Function

End Class




■子DLL(MV_Ext_AD.dll)
Imports Microsoft.MetadirectoryServices

Public Class MVExtensionObject
  Implements IMVSynchronization

  Public Sub Initialize() Implements IMvSynchronization.Initialize
    ' TODO: Add initialization code here
  End Sub

  Public Sub Terminate() Implements IMvSynchronization.Terminate
    ' TODO: Add termination code here
  End Sub

  Public Sub Provision(ByVal mventry As MVEntry) Implements IMVSynchronization.Provision
    Select Case mventry.ObjectType
      Case "person"
        Dim conMA As ConnectedMA = mventry.ConnectedMAs("MA_AD")
        Dim strCN As String = mventry("employeeID").Value.ToString
        Dim strRDN As String = "CN=" & strCN
        Dim refDN As ReferenceValue = conMA.EscapeDNComponent(strRDN).Concat
("ou=users,ou=ilm2007objects,dc=ilm,dc=local")
        Dim numConns As Integer
        Dim csentry As CSEntry

        numConns = conMA.Connectors.Count
        If numConns = 0 Then
          ' 新規エントリ→作成
          csentry = conMA.Connectors.StartNewConnector("user")
          csentry.DN = refDN
          csentry("unicodePwd").Values.Add("P@ssw0rd")
          csentry.CommitNewConnector()
        ElseIf numConns = 1 Then
          ' 既存エントリ
          csentry = conMA.Connectors.ByIndex(0)
          csentry.DN = refDN
        Else
          ' 例外
          Throw New UnexpectedDataException("MAに複数のコネクタオブジェクトが存在します")
        End If
      Case Else
    End Select
  End Sub

  Public Function ShouldDeleteFromMV(ByVal csentry As CSEntry, ByVal mventry As MVEntry) As Boolean Implements IMVSynchronization.ShouldDeleteFromMV
  End Function
End Class



最近はもう少しスマートに実装するようで、MAとExtensionDLLの名前をXMLファイルで定義して、MVExtension.dllから構成情報を読み出してロードする、という方法もとられているようです。

ILM"2"が出てきたらISR/OSRとの合わせ技のベストプラクティスが出てくるのかな?とは思っています。

0 件のコメント: