ヘッダーをスキップ
Oracle® Fusion Middleware Oracle Identity Managementアプリケーション開発者ガイド
11g リリース1(11.1.1)
B56242-05
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

5 JNDIに対するJava API拡張機能の使用

この章では、標準のディレクトリAPIにJavaの拡張機能を使用して、第3章で紹介した多くの操作を実行する方法について説明します。この章では使用例を示します。標準APIに対するOracleの拡張機能の詳細は、『Oracle Fusion Middleware Java API Reference for Oracle Internet Directory』を参照してください。

この章の項目は次のとおりです。

5.1 Java拡張機能のインストール

Java拡張機能は、LDAPクライアントのインストール時に標準のJava APIとともにインストールされます。APIとその拡張機能は、$ORACLE_HOME/jlib/ldapjclnt10.jarにあります。

5.2 oracle.ldap.utilパッケージを使用したLDAPオブジェクトのモデル化

Javaでは、LDAPエンティティ(ユーザー、グループ、レルム、アプリケーション)は、ハンドルではなくJavaオブジェクトとしてモデル化されます。このモデル化は、oracle.java.utilパッケージで行われます。他のすべてのユーティリティ機能は、個々のオブジェクトとして(GUIDなど)、あるいはユーティリティ・クラスの静的メンバー関数としてモデル化されます。

たとえば、ユーザーを認証するには、アプリケーションは次の手順に従います。

  1. 指定されたユーザー識別名で、oracle.ldap.util.Userオブジェクトを作成します。

  2. 必要なプロパティのすべてを備えたDirContext JNDIオブジェクトを作成するか、あるいはDirContextオブジェクトのプールからJNDIオブジェクトを取得します。

  3. User.authenticateUserメソッドを呼び出して、DirContextオブジェクトおよびユーザー資格証明への参照を渡します。

  4. 既存のDirContextオブジェクトのプールから取得したDirContextオブジェクトは、そのプールに戻します。

CやPL/SQLのプログラマとは異なり、Javaプログラマはオブジェクトを明示的に解放する必要がありません。このタスクは、Javaのガベージ・コレクション・メカニズムが実行します。

5.3 PropertySetCollection、PropertySetおよびPropertyクラス

Userクラス、SubscriberクラスおよびGroupクラスのほとんどのメソッドは、PropertySetCollectionオブジェクトを戻します。このオブジェクトは、1つ以上のLDAPエントリの集合を表しています。各エントリはPropertySetオブジェクトで表され、識別名で識別されます。PropertySetには、Propertyとして表される属性が含まれる場合があります。Propertyとは、そのPropertyが表す特定の属性に関する1つ以上の値の集合です。次に、これらのクラスの使用例を示します。

PropertySetCollection psc = Util.getGroupMembership( ctx,
                                                     myuser,
                                                     null,
                                                     true );
    // for loop to go through each PropertySet
    for (int i = 0; i < psc.size(); i++ ) {

    PropertySet ps = psc.getPropertySet(i);

   // Print the DN of each PropertySet
   System.out.println("dn:  " + ps .getDN());

   // Get the values for the "objectclass" Property
   Property objectclass = ps.getProperty( "objectclass" );

  
   // for loop to go through each value of Property "objectclass"
   for (int j = 0; j< objectclass.size(); j++) {

       // Print each "objectclass" value
       System.out.println("objectclass:  " + objectclass.getValue(j));
   }
}

エンティティmyuserは、Userオブジェクトです。pscオブジェクトには、myuserが属するネストされたグループがすべて含まれます。このコードは結果エントリをループし、各エントリのオブジェクト・クラス値をすべて出力します。

5.4 ユーザーの管理

ユーザー関連機能はすべてoracle.ldap.util.UserというJavaクラスで抽象化されます。このプロセスは、次のようになります。

  1. 識別名、GUIDまたは単純な名前に基づいて、oracle.ldap.util.Userオブジェクトを構成します。

  2. 必要な場合は、User.authenticateUser(DirContext, int, Object)を呼び出して、ユーザーを認証します。

  3. User.getProperties(DirContext)を呼び出して、ユーザー・エントリの属性を取得します。

  4. User.getExtendedProperties(DirContext, int, String[])を起動してユーザーの拡張プロパティを取得します。intはsharedまたはapplication-specificのどちらかです。String[]は必要なプロパティのタイプを表すオブジェクトです。String[]がnullの場合、指定されたカテゴリのすべてのプロパティが取得されます。

  5. PropertySetCollection.getProperties(int)を呼び出して、手順4で戻されたプロパティの解析に必要なメタデータを取得します。

  6. 拡張プロパティを解析し、アプリケーション固有のロジックを続行します。この解析は、アプリケーション固有のロジックによっても行われます。

5.5 ユーザーの認証

ユーザー認証は、ユーザーがログイン時に指定した資格証明とそのユーザーのディレクトリ内の資格証明を比較する一般的なLDAP操作です。Oracle Internet Directoryでは、次のものがサポートされています。

次に、APIを使用してユーザーを認証するためのコード例を示します。

 // User user1 - is a valid User Object
        try
        {
                user1.authenticateUser(ctx,
                    User.CREDTYPE_PASSWD, "welcome");
 
                // or
                // user1.authenticateUser(ctx, <any
attribute>, <attribute value>);
        }
        catch (UtilException ue)
        {
                // Handle the password policy error
accordingly
                if (ue instanceof PasswordExpiredException)
                        // do something
                else if (ue instanceof GraceLoginException)
                        // do something
        }

5.6 ユーザーの作成

subscriberクラスによってcreateUser()メソッドが使用され、プログラムによりユーザーが作成されます。ユーザー・エントリに必要なオブジェクト・クラスは、Oracle Delegated Administration Servicesを介して設定可能です。createUser()メソッドは、ユーザーの作成時に、クライアントが要件を理解し必須の属性に対して値を提供することを前提にしています。プログラマによって必須情報が提供されない場合、サーバーはエラーを戻します。

コード例の次のスニペットは、使用方法を示します。

// Subscriber sub is a valid Subscriber object
// DirContext ctx is a valid DirContext
 
// Create ModPropertySet object to define all the attributes and their values.
ModPropertySet mps = new ModPropertySet();
mps.addProperty(LDIF.ATTRIBUTE_CHANGE_TYPE_ADD,"cn", "Anika");
mps.addProperty(LDIF.ATTRIBUTE_CHANGE_TYPE_ADD,"sn", "Anika");
mps.addProperty(LDIF.ATTRIBUTE_CHANGE_TYPE_ADD,"mail",
"Anika@example.com");
 
// Create user by specifying the nickname and the ModPropertySet just defined
User newUser = sub.createUser( ctx, mps, true);
 
// Print the newly created user DN
System.out.println( newUser.getDN(ctx) );
 
// Perform other operations with this new user

5.7 ユーザー・オブジェクトの取得

subscriberクラスによってgetUser()メソッドが提供され、Userクラスのパブリック・コンストラクタと置き換えられます。このメソッドは、指定された情報に基づいてUserオブジェクトを戻します。

次に、使用方法を示します。

// DirContext ctx is contains a valid directory connection with
sufficient privilege to perform the operations
 
// Creating RootOracleContext object
RootOracleContext roc = new RootOracleContext(ctx);
 
// Obtain a Subscriber object representing the default
subscriber
Subscriber sub = roc.getSubscriber(ctx,
Util.IDTYPE_DEFAULT, null, null);
 
// Obtain a User object representing the user whose
nickname is "Anika"
User user1 = sub.getUser(ctx, Util.IDTYPE_SIMPLE, "Anika",
null);
// Do work with this user
 
The getUser() method can retrieve users based on DN, GUID
and simple name.  A getUsers() method is also available to
perform a filtered search to return more than one user at a
time.  The returned object is an array of User objects.
For example,
 
// Obtain an array of User object where the user's nickname
starts with "Ani"
User[] userArr = sub.getUsers(ctx, Util.IDTYPE_SIMPLE,
"Ani", null);
// Do work with the User array

5.8 レルムからのオブジェクトの取得

この項では、Java APIを使用してアイデンティティ管理レルムのオブジェクトを取得する方法について説明します。

RootOracleContextクラスはルートOracleコンテキストを表します。アイデンティティ管理レルムの作成に必要な情報のほとんどは、ルートOracleコンテキストに格納されています。RootOracleContextクラスではgetSubscriber()メソッドが提供されます。このメソッドは、subscriberクラスのパブリック・コンストラクタと置き換えられ、指定された情報に基づいてアイデンティティ管理レルム・オブジェクトを戻します。

次に、使用方法を示します。

// DirContext ctx contains a valid directory
// connection with sufficient privilege to perform the
// operations
 
// Creating RootOracleContext object
RootOracleContext roc = new RootOracleContext(ctx);
 
// Obtain a Subscriber object representing the
// Subscriber with simple name "Oracle"
Subscriber sub = roc.getSubscriber(ctx,
Util.IDTYPE_SIMPLE, "Oracle", null);
 
// Do work with the Subscriber object

5.9 例: Oracle Single Sign-Onログイン名の検索

次の例では、単純な名前、GUIDまたはDNがわかっている場合にユーザーのログイン名を検索する方法を示します。Oracle Single Sign-Onのログイン名は、ニックネームとも呼ばれます。

この例は、2つの部分から構成されています。

  1. このレルムへのニックネームの保存に使用されている属性を確認します。

  2. ユーザー・オブジェクトを取得し、ニックネーム属性の値を確認します。

import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import oracle.ldap.util.jndi.*;
import oracle.ldap.util.*;
import java.io.*; 
 
public class NickNameSearch {
 
   public static void main(String[] args)
      throws Exception
   {
      InitialLdapContext ctx = ConnectionUtil.getDefaultDirCtx( args[0],
                                     args[1], args[2],args[3]);
 
      RootOracleContext roc=new RootOracleContext(ctx);
      Subscriber sub = null;
      sub = roc.getSubscriber(ctx, Util.IDTYPE_DEFAULT, null, null) ;
 
      PropertySetCollection psc = sub.getProperties(ctx, 
                                     Subscriber.USER_NAMING_PROPERTIES, null);
    
      String nickNameAttribute = null;
      try
      {
          nickNameAttribute = (String) psc.getPropertySet(0).getProperty(Subscriber.USER_NAMING_ATTR_SIMPLE).getValue(0);
      }
      catch (Exception e)
      {
         // unable to retrieve the attribute name
         System.exit(0);
      }
      System.out.println("Nickname attribute: " + nickNameAttribute);      
 
      // Retrieve user using simple name, guid or DN
      User user = sub.getUser(ctx, Util.IDTYPE_SIMPLE,"orcladmin", null);
      System.out.println("user DN: " + user.getDN(ctx));
 
      // Retrieve nickname value using User object
      psc = user.getProperties(ctx, new String[]{ nickNameAttribute });
     
      String nickName = null;
      try
      {
          nickName = (String) psc.getPropertySet(0).getProperty(nickNameAttribute).getValue(0);
      }
      catch (Exception e)
      {
         // unable to retrieve the attribute value 
         System.exit(0);
      }
      System.out.println("Nickname : " + nickName);      
   }
}

5.10 ディレクトリ・サーバーの検出

次の新しいJavaクラス(パブリック・クラス)が導入されました。

public class oracle.ldap.util.discovery.DiscoveryHelper

このクラスでは、指定されたソースから特定の情報を検出するメソッドが提供されます。

表5-1 ディレクトリ・サーバー検出のメソッド

メソッド 説明
discover

指定されたソースから特定の情報を検出します。

setProperty

検出に必要なプロパティを設定します。

getProperty

プロパティの値にアクセスします。


既存のJavaクラスoracle.ldap.util.jndi.ConnectionUtilに、次の2つの新しいメソッドが追加されます。

5.11 例: ディレクトリ・サーバーの検出

次に、ディレクトリ・サーバー検出に使用するJavaプログラムの例を示します。

import java.util.*;
import java.lang.*;
import oracle.ldap.util.discovery.*;
import oracle.ldap.util.jndi.*;
 
public class dsdtest
{
  public static void main(String s[]) throws Exception
  {
    HashMap reshdl = new HashMap();
    String result = new String();
    Object resultObj = new Object();
    DiscoveryHelper disco = new
DiscoveryHelper(DiscoveryHelper.DNS_DISCOVER);
 
// Set the property for the DNS_DN
disco.setProperty(DiscoveryHelper.DNS_DN,"dc=us,dc=fiction,dc=com")
;
 
// Set the property for the DNS_DISCOVER_METHOD
disco.setProperty(DiscoveryHelper.DNS_DISCOVER_METHOD,
   DiscoveryHelper.USE_INPUT_DN_METHOD);
 
// Set the property for the SSLMODE
disco.setProperty(DiscoveryHelper.SSLMODE,"0");
 
// Call the discover method
int res=disco.discover(reshdl);
if (res!=0)
   System.out.println("Error Code returned by the discover method is :"+res) ;
 
// Print the results
printReshdl(reshdl);
}
 
public static void printReshdl(HashMap reshdl)
{
  ArrayList result = (ArrayList)reshdl.get(DiscoveryHelper.DIR_SERVERS);
 
if (result != null)
{
  if (result.size() == 0) return;
  System.out.println("The hostnames are :-");
  for (int i = 0; i< result.size();i++)
  {
      String host = (String)result.get(i);
      System.out.println((i+1)+".
'"+host+"'");
   }
  }
 }
}

5.12 Digest-MD5を使用したSASL認証の実行

JNDIを使用してSASL接続を確立する場合、javax.naming.Contextの次のプロパティを設定する必要があります。

後者にはプリンシパル名を設定します。この名前は、サーバー固有の形式です。次のいずれかのようになります。


注意:

SASL識別名は、SASLバインドをコールするAPIに渡される前に正規化される必要があります。SASLベリファイアを生成するために、Oracle Internet Directoryでは正規化された識別名のみがサポートされます。


5.13 例: SASL Digest-MD5のauth-intモードおよびauth-confモードの使用

次のコードでは、SASL Digest-MD5を使用したJava LDAP/JNDIの例を示します。

/* $Header: LdapSasl.java 27-oct-2005.11:26:59 qdinh Exp $ */
 
/* Copyright (c) 2003, 2005, Oracle. All rights reserved.  */
 
/*
  DESCRIPTION
   <short description of component this file declares/defines>
 
  PRIVATE CLASSES
   <list of private classes defined - with one-line descriptions>
 
  NOTES
   <other useful comments, qualifications, and so on.>
 
  MODIFIED    (MM/DD/YY)
   qdinh       04/23/03 - Creation
*/
 
/**
*  @version $Header: LdapSasl.java 27-oct-2005.11:26:59 qdinh Exp $
*  @author  qdinh   *  @since   release specific (what release of product did this appear in)
*/
 
package oracle.ldap.util.jndi;
 
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import oracle.ldap.util.jndi.*;
import oracle.ldap.util.*;
import java.lang.*;
import java.util.*;  
public class LdapSasl
{
   public static void main( String[] args)
       throws Exception
   {
 
    int numofargs;
 
    numofargs = args.length;
 
    Hashtable hashtable = new Hashtable();
 
    // Look through System Properties for Context Factory if it is available
    // then set the CONTEXT factory only if it has not been set
    // in the environment -
    // set default to com.sun.jndi.ldap.LdapCtxFactory
 
    hashtable.put(Context.INITIAL_CONTEXT_FACTORY,
          "com.sun.jndi.ldap.LdapCtxFactory");
    // possible valid arguments
    // args[0] - hostname
    // args[1] - port number
    // args[2] - Entry DN
    // args[3] - Entry Password
    // args[4] - QoP [ auth | auth-int | auth-conf ]
    // args[5] - SASL Realm
    // args[6] - Cipher Choice
    //    If QoP == "auth-conf" then args[6] cipher choice can be
    //     - des
    //     - 3des
    //     - rc4
    //     - rc4-56
    //     - rc4-40
 
    hashtable.put(Context.PROVIDER_URL, "ldap://"+args[0]+":"+args[1]);
        hashtable.put(Context.SECURITY_AUTHENTICATION, "DIGEST-MD5");
    System.out.println("hash put security dn: " + args[2]);
    hashtable.put(Context.SECURITY_PRINCIPAL, args[2] );
    hashtable.put(Context.SECURITY_CREDENTIALS, args[3] );
 
    // For Quality of Protection modes
    // 1. Authentication and Data Integrity Mode - "auth-int"
    // 2. Authentication and Data Confidentiality Mode  "auth-conf"
 
    //
    // hashtable.put("javax.security.sasl.qop",args[4]);
    hashtable.put("javax.naming.security.sasl.realm", args[5]);
   
    // Setup Quality of Protection
    //
    // System.out.println("hash sasl.qop: " + args[4]);
 
    hashtable.put("javax.security.sasl.qop",args[4]);
 
   
    if (numofargs > 4)
    {
    if (args[4].equalsIgnoreCase("AUTH-CONF"))
    {
 
        //  Setup a cipher choice only if QoP == "auth-conf"
        String strength = "high";
        String cipher = new String(args[6]);
                if (cipher.compareToIgnoreCase("rc4-40") == 0)
        strength = "low";
        else if (cipher.compareToIgnoreCase("rc4-56") == 0 ||
             cipher.compareToIgnoreCase("des")== 0 )
        strength = "medium";
        else if (cipher.compareToIgnoreCase("3des") == 0 ||
             cipher.compareToIgnoreCase("rc4") == 0)
        strength = "high";
 
        // setup cipher choice
        System.out.println("hash sasl.strength:"+strength);
        hashtable.put("javax.security.sasl.strength",strength);
    }
 
    // set maxbuffer length if necessary
    if (numofargs > 7 && !"".equals(args[6]))
        hashtable.put("javax.security.sasl.maxbuf", args[5].toString());
    }
 
 
    // Enable Debug --
    // hashtable.put("com.sun.jndi.ldap.trace.ber", System.err);
 
    LdapContext ctx = new InitialLdapContext(hashtable,null);
 
 
    // At this stage - SASL Digest -MD5 has been successfully
 
    System.out.println("sasl bind successful");
 
    // Ldap Search Scope Options
    //
    // - Search base - OBJECT_SCOPE
    // - One Level   - ONELEVEL_SCOPE
    // - Sub Tree    - SUBTREE_SCOPE
    //
        // Doing an LDAP Search
    PropertySetCollection psc = Util.ldapSearch(ctx,"o=oracle,dc=com","objectclass=*",SearchControls.OBJECT_SCOPE,
                           new String[] {"*"});
      // Print out the serach result
    Util.printResults(psc);
 
    System.exit(0);
 
 }                                                              }

5.14 LDAPトランザクションの使用

11gリリース1(11.1.1.6)の時点で、Oracle Internet Directory SDKはRFC 5805に定義されているトランザクションをサポートしています。


関連項目:

『RFC 5805 on Lightweight Directory Access Protocol (LDAP) Transactions』(http://www.ietf.org)


トランザクションはプロビジョニングなどいくつかのアプリケーションをサポートする必要があります。トランザクションがコミットされた場合、トランザクション更新内のすべての操作が成功するか、すべて失敗するかのいずれかです。Oracle Internet Directoryは、拡張操作およびコントロールのオブジェクト識別子を、ルートDSEでsupportedExtensionおよびsupportedControlとして公開します。

Oracle Internet Directory LDAPトランザクションは次のエンティティを使用します。

LDAPトランザクション内でのOracle Internet Directoryサーバーとクライアント間のリクエストおよびレスポンスの順序を次に示します。

  1. クライアントが、Oracle Internet Directoryサーバーにトランザクション開始リクエストを発行します。

  2. Oracle Internet Directoryサーバーが、トランザクション開始レスポンスにトランザクション識別子を設定し、成功のresultCode(0)でこのリクエストに応答します。不正な形式のリクエストなどの理由で失敗した場合、サーバーはエラーの種類を示す成功以外のresultCodeを含むトランザクション開始レスポンスで応答します。

    成功した場合に生成されてクライアントに送信されるこのトランザクション識別子は、後続のプロトコル・メッセージでこのトランザクションを識別するために使用されます。

  3. クライアントはサーバーから成功の結果コードを受け取ると、トランザクション識別子を持ったトランザクション仕様コントロールを各更新操作に添付して、単一トランザクションの一部として処理される操作であることを示します。有効な場合のレスポンスでは、Oracle Internet Directoryは成功を送信します。無効の場合、エラーの種類の詳細とともにresultCodeを含む、リクエストへの適切なレスポンスをクライアントに送信します。

  4. クライアントは、トランザクション識別子を持ったトランザクション仕様コントロールが添付された、すべてのトランザクション更新操作をOracle Internet Directoryサーバーに送信すると、トランザクション識別子を格納したトランザクション終了リクエストをOracle Internet Directoryサーバーに送信し、トランザクションの処理を要求します。コミットの値がTRUEの場合はトランザクションをコミットするリクエストを表し、値がFALSEの場合はトランザクションを中断するリクエストを表します。

  5. トランザクション中断のリクエストを受信すると、Oracle Internet Directoryサーバーは識別されたトランザクションを構成するすべての操作を破棄してトランザクションを中断し、成功のresultCode(0)を含むトランザクション終了レスポンスを返すことで処理の完了を表します。トランザクションをコミットするリクエストを受信すると、Oracle Internet DirectoryサーバーはDBに対して、トランザクション内のすべての操作に対して行った更新をコミットします。成功した場合、サーバーは、成功のresultCode(0)を含むトランザクション終了レスポンスを戻します。失敗した場合は、失敗の種類を表す成功以外のresultCodeを含むトランザクション終了レスポンスを戻します。

    トランザクション外でリクエストされたトランザクションや更新をサーバーがシリアライズする必要はありません。つまり、サーバーは1つ以上のクライアントからの異なるエントリ・セット上で動作する複数のコミット・リクエストを同時に処理することがあります。

  6. 前述のクライアントとサーバーとのやりとりの際、サーバーがトランザクションの仕様を継続できなくなった場合、サーバーはトランザクション中断通知を発行します。この通知を受信すると、クライアントはトランザクション識別子の使用をすべて中止する必要があり、トランザクションはnullおよびvoidとなります。トランザクションの一部として処理が予定されていたすべての操作は暗黙的に破棄されます。クライアントが引き続きこの識別子を使用しても、Oracle Internet Directoryサーバーからは失敗のresultCodeを含むレスポンスが戻されます。

  7. 前述のクライアントとサーバーとのやりとりの際、クライアントがOracle Internet Directoryサーバーへの接続を閉じた場合、サーバーは必要な接続関連のクリーンアップを実行します。

5.15 例: LDAPトランザクションの使用

この項では、LDAP拡張操作を使用したJNDIベースのLDAPトランザクションJavaクライアント・モジュールの開発に必要な手順の簡単なアウトラインを説明します。手順では、トランザクション開始リクエスト、トランザクション開始レスポンス、トランザクション終了リクエストおよびトランザクション終了レスポンスの4つのインタフェースの実装を行います。これら4つのインタフェースを実装するクラスは、トランザクション・セマンティクス内でLDAP更新操作を実行するコードで使用される必要があります。次のサンプルのコード・スニペットは、実装される4つのインタフェースと、トランザクション・セマンティクスでのLDAP更新操作のサンプルにおけるこれらの使用方法を示します。

5.15.1 トランザクション開始リクエスト・インタフェースの実装(LdapStartTxnReq.java)

import java.lang.*;
import java.util.*;
import java.io.*;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;

public class LdapStartTxnReq implements ExtendedRequest
{

    public static final String TXN_REQ_OID = "1.3.6.1.1.21.1";

    // constructor
    public LdapStartTxnReq()
    {
    }

    // Method for getting the request ID  
    public String getID() {      
      return TXN_REQ_OID; 
   }

    public byte[] getEncodedValue() {  
      return null;  // No value is needed for Start Txn request
    }

    public ExtendedResponse createExtendedResponse(String id, byte[] berValue,
                                                   int offset, int length)
           throws NamingException

    {
        return new LdapStartTxnRes(id, berValue, offset, length);    }
}

5.15.2 トランザクション開始レスポンス・インタフェースの実装(LdapStartTxnRes.java)

import java.lang.*;
import java.util.*;
import java.io.*;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
 
 
public class LdapStartTxnRes implements ExtendedResponse
{
  public String txnID;
 
  // Called by LdapStartTxnReq.createExtendedResponse()
  protected LdapStartTxnRes(String id, byte[] berValue, int offset, int length)
            throws NamingException
  {
    byte[] buff2 = new byte[length];
 
    System.arraycopy(berValue, offset, buff2, 0, length);
 
    try
    {
       this.txnID = new String(berValue, "UTF8");
    }
    catch (Exception e)
    {
      System.out.println(e);
    }
  }
 
  public String getTxnID()
  {
    return txnID;
  }
 
  // No op for our case
  public byte[] getEncodedValue()
  {
    return null;
  }
 
  public String getID()
  {
    return null; // as have no response ID.
  }
}

5.15.3 トランザクション終了リクエスト・インタフェースの実装(LdapEndTxnReq.java)

import java.lang.*;
import java.util.*;
import java.io.*;
import javax.naming.*;
import javax.naming.ldap.*;
import oracle.ldap.util.ber.*;


public class LdapEndTxnReq implements ExtendedRequest
{
    public  static final String TXN_END_REQ_OID = "1.3.6.1.1.21.3";
    private int sequenceTag = 0x30;
    private boolean commitValue;
    private String  controlValue;

    // constructor
    public LdapEndTxnReq(boolean commitVal, String controlVal)
    {
      this.commitValue = commitVal;
      this.controlValue = controlVal;
    }

    // Method to get End Txn Request ID
    public String getID() {
        return TXN_END_REQ_OID;
    }

    public byte[] getEncodedValue()
    {
      boolean encodeUTF8 = true;
      byte[] bytes = null;

      try
      {
        BEREncoder berElement = new BEREncoder();

        berElement.beginSeq(sequenceTag);

        berElement.encodeBoolean(this.commitValue);

        berElement.encodeString(this.controlValue, encodeUTF8);

        berElement.endSeq();
        bytes = berElement.getTrimmedBuf();

        return bytes;
      }
      catch (EncodeException e)
      {
         return null;
      }
    }

    public ExtendedResponse createExtendedResponse(String id, byte[] berValue,
                                                   int offset, int length)
           throws NamingException
    {
      return null;
    }
}

5.15.4 トランザクション終了レスポンス・インタフェースの実装(LdapEndTxnRes.java)

import java.lang.*;
import java.util.*;
import java.io.*;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;


public class LdapEndTxnRes implements ExtendedResponse
{
  // constructor
  LdapEndTxnRes(String id, byte[] berValue, int offset, int length)
                throws NamingException
  {
    ;
  }

  public String getTxnID()
  {
    return null;
  }

  public byte[] getEncodedValue()
  {
    return null;
  }

  public String getID()
  {
    return null;
  }
}

5.15.5 トランザクション・セマンティクス内のLDAP更新操作でのJavaおよび疑似コード・インタフェース・サンプル(LdapTxnOperation.java)

import java.lang.*;
import java.util.*;
import java.io.*;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
                .
                .
                .

public class LdapTxnOperation implements  …………….
{
    public static void main( String[] args )
    {
        try
        {             
            LdapContext  ctx;

            Perform ldapbind against OID server on the LDAP context ctx;

            If  bind is successful
            {
                /* Issue LDAP Start Transaction Request to OID server and 
                   receive its response */
                LdapStartTxnRes startResp = (LdapStartTxnRes)ctx.extendedOperation(new                                                                                                                           LdapStartTxnReq());
                /* Extract the transaction ID sent by OID server */
                String txnID = startResp.getTxnID();

Issue LDAP update operations (add, delete, modify) to OID server each containing
 the Transaction Control with ID 1.3.6.1.1.21.2 and value of the transaction ID;
 
/* Vendor's technical doc link is provided in Reference section below */

/* After done sending all update operations, issue LDAP End Transaction Request
 to OID server with your intention to either commit or abort the transaction and
 receive its response. */

If  want to commit the transaction
{ /* commit request */
    LdapEndTxnRes endResp = (LdapEndTxnRes)ctx.extendedOperation(new LdapEndTxnReq(true, txnID));
 }
 Else
 { /* abort request */
    LdapEndTxnRes endResp = (LdapEndTxnRes)ctx.extendedOperation(new  LdapEndTxnReq(false, txnID));
 }
              }
              catch( Exception e)
             {
                e.printStackTrace();
                return;
             }
             return ;
         }
      }