[SOA] Patching SOA Composite Instances in Oracle 12.2.1

原文はこちら。
https://blogs.oracle.com/integration/entry/patching_soa_composite_instances_in

Introduction

Composite Instance Patching12.2.1で導入された新機能で、これを使うと互換性のある変更をSOAコンポジット定義に対して実施し、長時間実行中のアクティブなインスタンスに適用することができます。特徴は、コンポジットを実行中のインスタンスに対してパッチを適用し、ランタイムにパッチを適用した後、失敗したインスタンスを回復できる、という点で、これを使うことで、コンポジットに対する緊急の修正を提供し、長時間実行中のインスタンスを停止せずに互換性/許可された変更をコンポジットに対して適用できます。パッチが適用された実行中のインスタンスがパッチによって修正されたビジネスプロセス、例えばBPELのTransformationに遭遇すると、ビジネスプロセスに適用された修正を受け取ります。
12.2.1以前では、コンポジットに小さな変更を加えたり、実行中のインスタンス、具体的には長時間実行中のインスタンスや、エラーホスピタルのインスタンスがそうした変更を確認する方法がありませんでした。代替策としては、既存のコンポジットのリビジョンをデプロイするか、新たなコンポジットのリビジョンを作成することですが、前者の場合、実行中のインスタンスが処理を停止してしまうこと、後者の場合、既存の実行インスタンスはそのまま実行できるものの、新しいリビジョンで導入された変更はわからない、という問題があります。そこで、12.2.1での新しいComposite Instance Patching機能を使用すると、重要な修正をタイムリーに適用し即時有効化できる、という点が、Oracle SOA Suiteのユニークな差別化要素です。
このエントリでは、(1) コンポジットに加えることのできる互換性のある変更について紹介するとともに、(2) コンポジットパッチで無効な変更を加える心配なく、迅速かつ簡単にパッチを設計できる、JDeveloperへの機能強化を説明し、(3) SOA Suiteへコンポジットインスタンスへのパッチをビルド、検証、デプロイで使う手順を紹介します。

Compatible Composite Changes

前述の通り、コンポジットに対して加えることができ、実行中のインスタンスとの互換性があると見なされる変更は限られています。Composite Instance Patchingで扱える互換性のある変更をいくつかご紹介しましょう。
  • スキーマに関係しないXSLTの変更
  • フォルトポリシー、センサーデータ、アナリティクスデータへの変更
  • BPELへの互換性のある変更。例えば同期/非同期呼び出し、Transformationアクティビティ、Assignなど
  • JCA Adapterの構成プロパティ
  • コンポジット参照(Reference)のトークン値の変更
対して、Composite Instance Patchingで扱えない、互換性のない変更は以下のようなものがあります。
  • コンポジットあーティファクトの削除や名前変更
  • バインディングプロパティの更新
  • WSDLやスキーマ定義への変更
  • XQueryマッピングへの変更
  • BPELのReceive、構造化アクティビティ、Assignにおけるマッパー(ソース、ターゲット、スキップ条件)
どれが互換性のある変更で、どれが非互換なのかを正確に知っておく必要はありません。こうしたルールはJDeveloperのSOA Patch Developerモードで把握しており、自動的にパッチを作成できない変更を無効化します。

Composite Instance Patch Development in JDeveloper

コンポジットインスタンスへのパッチ作成を簡単にするため、数多くの機能強化がJDeveloperになされました。第1の変更点は、新たなSOA Patch Developerロールの導入です。JDeveloperを立ち上げたときに、最初に自身の要求に適うロールを選択する必要があります。


選択されたロールでは、メニュー、プリファレンス、新規ギャラリ、およびダイアログ上の個々のフィールドまでを含む、不要な項目をJDeveloperから除去するようにJDeveloper環境を仕立てます。選択したロールによって、利用可能な機能とオプションが決まります。SOA Patching Developerロールの場合、利用可能なアクション、エディタ、ウィザードによってユーザーが制限され、コンポジットインスタンスへのパッチ作成のため、互換性のある変更に関連するアクションのみ許可されます。
すでにJDeveloperでプロジェクトを開いている場合は、Oracle JDeveloperのメニューバーから、[ツール]> [ロールの切替え]>[SOA Patch Developer]とたどって、SOA Patch Developerモードに切り替える必要があります。 新たなロールを選択すると、変更を有効にするためにJDeveloperを再起動するように求められます。





新しいコンポジット・インスタンス・パッチを作成する場合、出発点は既存のデプロイ済みSOAコンポジットのリビジョンです。SOA Patch Developerロールである間、コンポジットへの後の変更は新たなpatch.xmlファイルでトラッキングされています。このファイルは変更されたアーティファクトファイルが最初に保存される際にプロジェクトディレクトリ内のSOA/SCA-INFディレクトリに自動的に生成されます。patch.xmlファイルは、SOA Patch Developerモードでコンポジットを変更、保存するたびに更新されます。patch.xmlファイルはメニューバーの[アプリケーション]>[概要の表示]を開き、XMLファイルの配下にあるpatch.xmlを選択すると表示できます。
プロジェクトにpatch.xmlがあるかないかで、コンポジット・パッチを作成しているのか、新規リビジョンを作成しているのかをJDeveloperに伝えます。SOA Patch Developerロールでない場合にpatch.xmlファイルを含むプロジェクトを開くと、以下の3個の方法のうち一つをとるよう求められます。
  1. SOA Patch Developerロールに切り替え、パッチ作成を継続する
  2. 現在のロールでプロジェクトを閉じる(つまり何もしない)
  3. project.xmlファイルを削除し、新しいコンポジット・リビジョンを作成する

なお、project.xmlファイルの削除を選択した場合、SOA Patch Developerロールで実施したコンポジットへの変更は消失しませんが、パッチ用にアーティファクトを修正したその記録はなくなることにご注意ください。

[訳注]
本来ならば、[Patch File Found]を意味する「パッチ・ファイルが見つかりました」となるべきところが、翻訳ミスで逆の意味になってしまっています。現在修正を依頼しています。


なお、英語の場合はこんな感じです。


patch.xmlファイルで参照されているアーティファクトのみコンポジットインスタンスパッチのデプロイメントアーカイブに取り込まれます。パッチアーカイブには通常のデプロイメント・アーカイブ(.sarファイル)にあるファイルの完全なセットは含まれていませんので、「少ない(sparse)」パッチ・アーカイブとも呼ばれます。パッチ・アーカイブを作成するためには、実行環境に変更をデプロイするためのデプロイメント・プロファイルを作成することから始めます。以下の手順を踏んでJDeveloperを使ってパッチのデプロイメント・プロファイルを作成します。
  1. [アプリケーション]内のプロジェクト名を右クリックし、[デプロイ]>[プロジェクト名]を選択します。新規デプロイメント・プロファイルを選択してもよいですし、以前に作成したパッチのデプロイメント・プロファイルを選択してもかまいません。[プロジェクト名]のデプロイウィザードが現れます。
  2. プロジェクトをデプロイするために、ウィザードの全手順を完了します。デプロイの構成(Deploy Configuration、なぜか日本語表示では構成のデプロイになっていますが...)画面では新たなバージョンの作成や既存バージョンの上書きはできないことに注意してください。これは別のバージョンを作成せず、実行中のインスタンスに影響を与えずに、パッチを実行環境にデプロイするためです。
  3. [終了]をクリックして、パッチのjarファイルを作成します。プロジェクト名/deployディレクトリにパッチのjarファイルがプロジェクトオリジナルのjarファイルに加えて格納されているはずです。デフォルトでは、パッチのjarファイルの名前はsca_{プロジェクト名}_patch.jarという表記ルールに則っています。
その他にも、AntやWLSTコマンドラインツールを使ってパッチ・アーカイブを作成することができます。パッチ・アーカイブをAntで作成する場合、以下のようにスクリプトを呼び出します。
ant -f  jdev_home/soa/bin/ant-sca-package.xml  -DcompositeDir=path_to_project_soa_folder -DcompositeName=composite_name  -Drevision=composite_revision
WLSTコマンドラインツールを使ってパッチ・アーカイブを作成する場合、sca_packagePatchコマンドを使います。sca_packagePatchコマンドの構文や引数に関する詳細情報は、ヘルプコマンド help(‘sca_packagePatch’) を使って確認できます。
例として、 sca_packagePatch('/home/HelloWorld/SOA','HelloWorld','1.0') とすると、/home/HelloWorld/SOA というディレクトリにコンポジット・アーティファクトのためのパッチ・アーカイブが作成されます。

Deploying the Composite Instance Patch

WLSTコマンドラインツールを使ってパッチのjarファイルを検証、デプロイすることができます。sca_validatePatchとsca_patchCompositeという2個のコマンドを使い、パッチを検証、デプロイします。以下の手順を踏んで、パッケージ済みjar(コンポジットのSARファイル)を検証し、実行環境にデプロイします。
  • sca_validatePatchコマンドを使用して、パッチのjarファイルを検証します。sca_validatePatchコマンドの構文および引数の詳細情報は、help('sca_validatePatch')で確認できます。例として、sca_validatePatch('http://my_soa_server:8001', 'weblogic',  'welcome', '/home/sca_HelloWorld_patch.jar') を実行した場合、sca_HelloWorld_patch.jar というパッチファイルが正常にmy_soa_serverのSOAサーバ実行環境にデプロイできるかどうかを確認します。コンポジット・パッチの検証で問題がないことが確認されると、「コンポジット・パッチは正常に検証されました("Composite patch has been validated successfully")」というメッセージが表示されるはずです。
  • sca_patchCompositeコマンドを使用して、パッチのjarファイルを実行環境にデプロイします。help(‘sca_patchComposite’)でsca_patchCompositeコマンドの構文および引数の詳細情報を取得することができます。例えば、sca_patchComposite('http://my_soa_server:8001', 'weblogic', 'welcome', '/home/sca_HelloWorld_patch.jar') とすると、sca_HelloWorld_patch.jarというパッチのjarファイルを使ってmy_soa_serverの実行環境上のHelloWorldコンポジットにパッチを適用します。パッチが正常に適用されると、「コンポジットは正常にパッチが適用されました(Composite has been patched successfully)」のメッセージが表示されるはずです。デプロイ前にパッチのjarファイルを検証するのを忘れたとしても、心配する必要はありません。デプロイメント・アクション中に、コンポジットのリビジョンをアップデートする前にサーバ側で検証チェックを実施するので、非互換の変更によって実行環境へ誤ってアップロードされることはありません。
Enterprise Manager Fusion Middleware Controlで以前に失敗したフローインスタンスを確認していて、このパッチを適用後リカバリが可能な場合、リカバリしてみてください。

JDeveloper-Based Patching Process

Composite Instance Patchingを、正式なビルドプロセスに組み込む方法には様々考えられますが、その一つをご紹介しましょう。
  1. 開発者は「SOAパッチ開発(SOA Patch Developer)」モードでJDeveloperを起動し、、ソースコントロールで見つかった既存のコンポジット用の互換性のある変更/修正のセットを作成します
  2. ソース管理の"patching"ブランチに変更を保存し戻します。
  3. 「互換性のある」コンポジットの修正のデプロイメント・アーカイブをソース管理からantスクリプトを使って作成し、後続のテスト作業のため、テスト/ステージング環境にWLSTコマンドを使ってデプロイします1。
  4. もしくは、デプロイメント・アーカイブをJDeveloperで作成し、その後のテストのために、WLSTコマンドを使用して開発環境にデプロイします1。
  5. このアーカイブを本番環境にデプロイし、実行インスタンスが新しいメタデータを使って処理を継続します1。
1ランタイム検証・互換性のチェックは、変更されたアーティファクトに対してパッチデプロイ中に実行されます。
JDev Patching Process


Conclusions

新機能であるComposite Instance PatchingがSOA Suite 12.2.1で導入されました。これを使うとコンポジットに対する緊急の修正を展開し、長時間実行中のインスタンスが取り込むことができるようになります。この機能はOracle Integration Continuous Availabilityに含まれています。その他の情報は、以下のドキュメントをご覧ください。
Oracle® Fusion Middleware Developing SOA Applications with Oracle SOA Suite 12c (12.2.1)
Patching Running Instances of a SOA Composite
http://docs.oracle.com/middleware/1221/soasuite/develop/GUID-F2B6386E-0F68-4797-96D2-196800394FEF.htm#SOASE-GUID-4010E817-DF41-4CCC-B9CC-196EE6AB8905

[Java] Moving to a Plugin-Free Web

原文はこちら。
https://blogs.oracle.com/java-platform-group/entry/moving_to_a_plugin_free

2015年末までに、多くのブラウザベンダーが標準ベースのプラグインサポートをやめたり、廃止のタイムラインを発表しました。具体的には、Flash、Silverlight、Java、その他のプラグインベースのテクノロジーを埋め込む機能を取り除く、というものです。
NPAPI Plugin Perspectives and the Oracle JRE
https://blogs.oracle.com/java-platform-group/entry/npapi_plugin_perspectives_and_the
http://orablogs-jp.blogspot.jp/2015/10/npapi-plugin-perspectives-and-oracle-jre.html
モダンブラウザのベンダーは自身の製品でのプラグインサポートを制限、取りやめようとしているので、Javaブラウザプラグインに依存するアプリケーションの開発者は代替策を検討する必要があります。例えば(ブラウザプラグインに依拠している)Java Appletからプラグインが不要なJava Web Startテクノロジーに移行するといった具合です。
Java™ Web Start
http://docs.oracle.com/javase/8/docs/technotes/guides/javaws/
http://docs.oracle.com/javase/jp/8/docs/technotes/guides/javaws/
(訳注)
なぜかJava 8のドキュメントなのにJava 7という表記になっているのはご愛敬...。

OracleはJavaブラウザプラグインをJDK 9でdeprecate(非推奨)にする予定です。 将来のJava SEリリースでは、Oracle JDK およびJREからこのテクノロジーをなくす予定です。

JDK 9のEarly Accessリリースは以下のURLからダウンロードし、テストできます。
JDK 9 Project - Building the next generation of the JDK platform
http://jdk9.java.net 
背景や様々な移行の選択肢に関する情報は以下のリンクのホワイトペーパーをご覧ください。
Migrating from Java Applets to plugin-free Java technologie
http://www.oracle.com/technetwork/java/javase/migratingfromapplets-2872444.pdf

[WLS, Java] New EJB 3.2 feature - Modernized JCA-based Message-Driven Bean

原文はこちら。
https://blogs.oracle.com/WebLogicServer/entry/new_ejb_3_2_feature

WebLogic Server 12.2.1は、Java EE7仕様に完全に互換性をもつ実装です。このリリースのWebLogic ServerにおけるEJBコンテナでの大きな改善点の一つに、MDB(メッセージ駆動型Bean)がメソッド無しでリスナーインターフェースを実装できる点があります。このようなno-methodリスナーインタフェースを使用する場合、すべてのstaticではないBeanクラス(およびjava.lang.Object以外のBeanクラスのスーパークラス)のパブリックメソッドは、メッセージ・リスナー・メソッドとして公開されます。
それでは、ステップバイステップでサンプルを開発してみましょう。e-Commerceのwebサイトは、製品が売買されると、その売買イベントをJMS Queue、buyQueueとsellQueueそれぞれに送信するものとします。コネクタは、キューをリスニングし、MDBの非静的パブリック・メソッドを実行して、永続ストアにイベントのレコードを書き込みます。

1. Define a no-methods message listener interface

今回のサンプルでは、メッセージ・リスナー・インターフェースのNoMethodsListenerIntfにはメソッドがありません。
List 1 - No-methods message listener interface
public NoMethodsListenerIntf {
}

2. Now define the bean class

MDBのクラスには、productBoughtとproductSoldという、二つの非静的パブリックメソッドがあります。そのため、両方ともメッセージリスナーメソッドとして公開されています。コネクタがsellQueueから製品販売イベントを取得すると、MDBのproductSoldを呼び出します。製品購入イベントでも同様です。コネクタが実行すべきターゲット・メソッドであることを示すよう、productSoldメソッドとproductBoughtメソッドに対して@EventMonitorで注釈を付けます。これらの2つのメソッドは、データベースまたは他の永続ストアにレコードを永続化します。
ほかにも非静的パブリック・メソッドを定義することができますが、どれををコネクタが実行するのかはコネクタ次第です。
List 2 - Message-Driven Bean
@MessageDriven(activationConfig = {
  @ActivationConfigProperty(propertyName = "resourceAdapterJndiName", propertyValue = "eis/TradeEventConnector")
})

public class TradeEventProcessingMDB implements NoMethodsListenerIntf {
  @EventMonitor(type = "Retailer")
  public void productSold(long retailerUUID, long productId) {
    System.out.println("Retailer [" + retailerUUID + "], product [" + productId + "] has been sold!");
    // persist to database
  }

  @EventMonitor(type = "Customer")
  public void productBought(long customerId, long productId) {
    System.out.println("Customer [" + customerId + "] has bought product [" + productId + "]!");
    // persist to database
  }
}
EventMonitor注釈を以下のように設定します。
List 3 - EventMonitor annotation
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface EventMonitor {
  public String type();
}
このMDBをWebLogic Serverにデプロイする際、EJBコンテナはこのMDBがEJB 3.2互換のMDBであることを検知します。resourceAdapterJndiNameの値を指定し忘れていると、WebLogic Serverが適切なコネクタリソースを見つけようとします。例えば、(現在のアプリケーションスコープ、もしくはサーバ全体のグローバルスコープでアクセス可能なコネクタのうち)同じno-methodメッセージリスナーインターフェースのサポートを宣言しているコネクタを見つけようとします。
適切なコネクタが見つかり、MDBと紐付けられた場合、コネクタはBeanクラス定義を読み取り、分析することができます。

3. Developing a connector that is used to associate with message-driven bean

コネクタアプリケーションでは、MessageEndpointFactoryのgetEndpointClass()メソッドを使ってBeanクラス定義を取得し、@EventMonitorで注釈が付いている場合にはすべてのメソッドを検査します。その後、javax.jms.MessageListenerをBeanクラスのターゲットメソッドを使って作成し、イベント・キューで待機します。
List 4 - trade event connector
@Connector(
    description = "This is a sample resource adapter",
    eisType = "Trade Event Connector",
    vendorName = "Oracle WLS",
    version = "1.0")

public class TradeEventConnector implements ResourceAdapter, Serializable {
  // jms related resources
  ......

  private static final String CALLBACK_METHOD_TYPE_RETAILER = "Retailer";
  private static final String CALLBACK_METHOD_TYPE_CUSTOMER = "Customer";

  @Override
  public void endpointActivation(MessageEndpointFactory mef, ActivationSpec activationSpec)
      throws ResourceException {
    try {
      Class<?> beanClass = mef.getEndpointClass(); // retrieve bean class definition
      ......
      jmsContextForSellingEvent = ...; // create jms context
      jmsContextForBuyingEvent = ...;
      jmsConsumerForSellingEvent = jmsContextForSellingEvent.createConsumer(sellingEventQueue);
      jmsConsumerForBuyingEvent = jmsContextForBuyingEvent.createConsumer(buyingEventQueue);

      jmsConsumerForSellingEvent.setMessageListener(createTradeEventListener(mef, beanClass, CALLBACK_METHOD_TYPE_RETAILER));
      jmsConsumerForBuyingEvent.setMessageListener(createTradeEventListener(mef, beanClass, CALLBACK_METHOD_TYPE_CUSTOMER));

      jmsContextForSellingEvent.start();
      jmsContextForBuyingEvent.start();
    } catch (Exception e) {
      throw new ResourceException(e);
    }
  }

  private MessageListener createTradeEventListener(MessageEndpointFactory mef, Class<?> beanClass, String callbackType) {
    for (Method m : beanClass.getMethods()) {
      if (m.isAnnotationPresent(EventMonitor.class)) {
        EventMonitor eventMonitorAnno = m.getAnnotation(EventMonitor.class);
        if (callbackType.equals(eventMonitorAnno.type())) {
          return new JmsMessageEventListener(mef, m);
        }
      }
    }
    return null;
  }

  @Override
  public void endpointDeactivation(MessageEndpointFactory mef, ActivationSpec spec) {
    // deactivate connector
  }
  ......
}
関連づけられたコネクタのアクティベーション・スペックを以下のように定義します。
List 5 - the activation spec
@Activation(
    messageListeners = {NoMethodsListenerIntf.class}
  )
public class TradeEventSpec implements ActivationSpec, Serializable {
  ......
}

4. Developing a message listener to listen on the event queue.

メッセージリスナのonMessage()が呼び出されると、MessageEndpointFactoryを使ってメッセージエンドポイントを作成し、このメッセージエンドポイントのターゲットメソッドを呼び出します。
List 6 - jms message listener
public class JmsMessageEventListener implements MessageListener {
  private MessageEndpointFactory endpointFactory;
  private Method targetMethod;

  public JmsMessageEventListener(MessageEndpointFactory mef, Method executeTargetMethod) {
    this.endpointFactory = mef;
    this.targetMethod = executeTargetMethod;
  }

  @Override
  public void onMessage(Message message) {
    MessageEndpoint endpoint = null;
    String msgText = null;
    try {
      if (message instanceof TextMessage) {
        msgText = ((TextMessage) message).getText();
      } else {
        msgText = message.toString();
      }
      long uid = Long.parseLong(msgText.substring(0, msgText.indexOf(",")));
      long pid = Long.parseLong(msgText.substring(msgText.indexOf(",") + 1));

      endpoint = endpointFactory.createEndpoint(null);
      endpoint.beforeDelivery(targetMethod);
      targetMethod.invoke(endpoint, new Object[]{uid, pid});
      endpoint.afterDelivery();
    } catch (Exception e) {
      // log exception
      System.err.println("Error when processing message: " + e.getMessage());
    } finally {
      if (endpoint != null) {
        endpoint.release();
      }
    }
  }
}

5. Verify the application

イベントの構文は、カンマで区切られた2個の数字、例えば328365,87265で構成されているものとします。前者の数字は、顧客や小売店のIDで、後者の数字は、製品IDです。
そのようなイベントをイベントキューに送信すると、MDBがそのイベントを永続化することがわかるでしょう。We assume that the syntax of the event is composed

[WLS] Weblogic 12.2.1 Multitenancy Support for Resource Adapter

原文はこちら。
https://blogs.oracle.com/WebLogicServer/entry/weblogic_12_2_1_multi

WebLogic Server 12.2.1の主要な機能の一つにMultitenancyのサポートがあります。このコンセプトについては、Tim Quinnの以下のエントリが非常に参考になります。
Domain Partitions for Multi-tenancy in WebLogic Server 12.2.1
https://blogs.oracle.com/WebLogicServer/entry/domain_partitions_for_multi_tenancy
http://orablogs-jp.blogspot.jp/2015/11/domain-partitions-for-multi-tenancy-in.html 
リソースアダプタの場合は、ドメインパーティションへのデプロイのほかに、パーティションのリソースグループまたはリソースグループテンプレートにデプロイすることもできます。これは、コンソールでリソースアダプタをデプロイするときに、リソースグループのスコープまたはリソースグループテンプレートのスコープを選択することで可能になっています。下図は、WebLogic Server管理コンソールのデプロイメントのページを示しています。この例では、Partition1にリソースグループPartition1-rgとリソースグループテンプレートTestRGTがあります。

Deploy RA to MT in Console
「グローバル(Global)」スコープを選択すると、リソースアダプタはドメインパーティションにデプロイされます。「TestRGT」スコープを選択すると、リソースアダプタはリソースグループテンプレートTestRGTにデプロイされます。Partition1のリソースグループがTestRGTを参照する場合、リソースアダプタはParttion1にデプロイされます。「Partition1のPartition1-rg(Partition1-rg in Partition1)」を選択した場合、リソースアダプタはPartition1にデプロイされます。

マルチテナント環境でのデプロイメントについては、Hong Zhangのエントリが非常に参考になります。
Multi Tenancy Deployment
https://blogs.oracle.com/misty/entry/multi_tenancy_deployment
リソースアダプタを別のパーティションにデプロイする場合、異なるパーティションのこれらのリソースはお互いに干渉しあうことはありません。その理由は以下の通りです。
  1. あるパーティションのResource adapterのJNDIリソースを別のパーティションが検索することはできません。同一パーティションに紐付けられている炉ソースアダプタリソースのみ検索できます。
  2. 別のパーティションにデプロイされたリソースアダプタjは、別のクラスローダがリソースアダプタアーカイブにパッケージされたリソースアダプタのクラス群をロードします。別のパーティションがロードしたとあるリソースアダプタクラス群を使うようなことは心配無用です。
  3. 何らかの形で別のパーティションに属する以下のリソース・アダプターのリソース・オブジェクトのいずれかへの参照を取得したとしても、使用することはできません。そのオブジェクトのメソッドを呼び出すと例外が発生します。
    • javax.resource.spi.work.WorkManager
    • javax.resource.spi.BootstrapContext
    • javax.resource.spi.ConnectionManager
    • javax.validation.Validator
    • javax.validation.ValidatorFactory
    • javax.enterprise.inject.spi.BeanManager
    • javax.resource.spi.ConnectionEventListener
リソースアダプタをデプロイした後に、WebLogic Scriptiing Tool (WLST)を使って、ServerRuntimeの下のConnectorServiceRuntimeディレクトリから、ドメインリソースアダプタのランタイムMBeanにアクセスすることができます。
Oracle® Fusion Middleware Oracle WebLogic Scripting Tool 12c (12.2.1)
Using the WebLogic Scripting Tool
http://docs.oracle.com/middleware/1221/wls/WLSTG/using_wlst.htm#WLSTG118
View Connector RuntimeMBean in WLST
上の例では、jca_raというリソースアダプタがドメインパーティションにデプロイされているので、ConnectorServiceRuntime/ConnectorService以下でランタイムMBeanを確認することができます。jms-internal-notran-adpとjms-internal-xa-adpも出てきています。これらはWebLogic Serverの内部リソースアダプタです。

では、パーティションにデプロイされたリソースアダプタはどのように見えるのでしょうか。これらはPartitionRuntimesの下にあります。
View MT Connector RuntimeMBean in WLST

上の例では、'jca_ra'という名前のリソースアダプタがPartition1にデプロイされています。

リソースアダプタのランタイムMBeanは、JMXを使って取得することもできます。
Oracle® Fusion Middleware Developing Custom Management Utilities Using JMX for Oracle WebLogic Server 12c (12.2.1)
Accessing WebLogic Server MBeans with JMX
http://docs.oracle.com/middleware/1221/wls/JMXCU/accesswls.htm#JMXCU144
JMXServiceURL serviceURL = new JMXServiceURL("t3", hostname, port, "/jndi/weblogic.management.mbeanservers.domainruntime");
Hashtable h = new Hashtable();
h.put(Context.SECURITY_PRINCIPAL, user);
h.put(Context.SECURITY_CREDENTIALS, passwd);
h.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, "weblogic.management.remote");
h.put("jmx.remote.x.request.waiting.timeout", new Long(10000));
JMXConnector connector = JMXConnectorFactory.connect(serviceURL, h);
MBeanServerConnection connection = connector.getMBeanServerConnection();
Set<ObjectName> names = connection.queryNames(new ObjectName("*:Type=ConnectorComponentRuntime,Name=jca_ra,*"), null);
for (ObjectName oname : names) {
    Object o = MBeanServerInvocationHandler.newProxyInstance(connection, oname, ConnectorComponentRuntimeMBean.class, false);
    System.out.println(o);
}
'jca_ra'というリソースアダプタをドメインスコープとPartition1にデプロイしてあるドメインで上のサンプルコードを実行すると、以下のような結果が得られます。
[MBeanServerInvocationHandler]com.bea:Name=jca_ra,ServerRuntime=admin,Location=admin,Type=ConnectorComponentRuntime,ApplicationRuntime=jca_ra
[MBeanServerInvocationHandler]com.bea:Name=jca_ra,ServerRuntime=admin,Location=admin,Type=ConnectorComponentRuntime,ApplicationRuntime=jca_ra,PartitionRuntime=Partition1
Partition1にデプロイされたリソースアダプタの接続プール・ランタイムMBean(ConnectorComponentRuntime) にはPartitionRuntime属性が付いていることを確認できます。そのため、Partition1のリソースアダプタのランタイムMBeanを以下のコードで抽出することができます。
connection.queryNames(new ObjectName(
                   "*:Type=ConnectorComponentRuntime,Name=jca_ra,PartitionRuntime=Partition1,*"), null);

[Java, WLS] WLS 12.2.1 launch - Servlet 3.1 new features

原文はこちら。
https://blogs.oracle.com/WebLogicServer/entry/wls_12_2_1_launch

Introduction

WebLogic Server 12.2.1ではServlet 3.1仕様の新機能をサポートしています。Servlet 3.1仕様はServlet仕様のメジャーバージョンであり、このバージョンの仕様は、主にノンブロッキングIOとHTTPプロトコルのアップグレード機能をServletContainerに導入し、最新のWebアプリケーション開発に使えるようにしました。ノンブロッキングIOは、Webコンテナのスケーラビリティ改善への増大する要求への対策であるとともに、Webコンテナで同時に処理できる接続数を増やすことができます。ServletコンテナのノンブロッキングIOを使うと、開発者はデータが利用可能になるとデータを読めたり、可能であれば書きこんだりすることができます。また、このバージョンでは、セキュリティと機能強化のためのいくつかのマイナーな変更も導入しました。
JSR 340: Java Servlet 3.1 Specification
https://jcp.org/en/jsr/detail?id=340

1 Upgrade Processing

1.1 Description

HTTP/1.1では、general-headerのアップグレードを使うと、サポートされた利用したい追加の通信プロトコルをクライアントは指定することができます。サーバはプロトコルを切り替えることが適当と認める場合には、新しいプロトコルを使って後続の通信を実施します。
Servletコンテナは、HTTPアップグレードメカニズムを提供します。しかし、Servletコンテナ自体は、アップグレード対象のプロトコルに関する知識を有しません。プロトコル処理はHttpUpgradeHandlerにカプセル化されており、ServletコンテナとHttpUpgradeHandler間のデータの読み込みや書き込みはバイトストリームで行われます。
プロトコルのアップグレードリクエストを受信した場合、Servletは、HttpServletRequest.upgrade()メソッドを呼び出してアップグレードプロセスを開始することができます。このメソッドは、指定されたHttpUpgradeHandlerクラスをインスタンス化します。戻されたHttpUpgradeHandlerインスタンスをさらにカスタマイズすることができます。アプリケーションがクライアントに対して適切なレスポンス準備し、送信します。Servletのサービスメソッドを終了した後、Servletコンテナは、すべてのフィルタ処理を完了し、HttpUpgradeHandlerが処理するよう接続をマークします。そして、HttpUpgradeHandlerのinit()メソッドを呼び出し、プロトコルハンドラがデータストリームへアクセスできるよう、WebConnectionを渡します。
Servletフィルタは最初のHTTPリクエストとレスポンスを処理するだけで、その後の通信に関与しません。つまり、リクエストがアップグレードされると、呼び出されません。HttpUpgradeHandlerは、ノンブロッキングIOを利用して、メッセージを消費、生成することができます。HTTPアップグレードの処理中、開発者はServletInputStream、ServletOutputStreamへのスレッドセーフなアクセスのための責任を負います。アップグレード処理が完了すると、HttpUpgradeHandler.destroyが呼び出されます。

1.2 Example

この例では、クライアントがサーバに対してリクエストを送信し、サーバがリクエストを受け付け、レスポンスを返し、HttpUpgradeHandler.init()メソッドを呼び出してダミープロトコルを使って通信を継続します。クライアントはハンドシェイクの間、リクエスト・レスポンスヘッダを表示します。

Client

クライアントはHTTPアップグレードのリクエストを発行します。
@WebServlet(name = "ClientTest", urlPatterns = {"/"})
public class ClientTest extends HttpServlet {
  protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String reqStr = "POST " + contextRoot + "/ServerTest HTTP/1.1" + CRLF;
    ...
    reqStr += "Upgrade: Dummy Protocol" + CRLF;

    // Create socket connection to ServerTest
    s = new Socket(host, port);
    input = s.getInputStream();
    output = s.getOutputStream();

    // Send request header with data
    output.write(reqStr.getBytes());
    output.flush();
  }
}
この例では、HTTP/1.1ヘッダフィールドをUpgrade: Dummy Protocolに変更しようとしています。さーば はプロトコルアップグレードのリクエストを受け入れるかどうかを判断します。

Server

ServerTest.javaはリクエストヘッダ中のUpgradeフィールドをチェックします。アップグレードリクエストを受け入れる場合、サーバはProtocolUpgradeHandler(HttpUpgradeHandlerの実装)を呼び出します。クライアントが指定したUpgradeプロトコルをサーバがサポートしない場合、404を返します。
@WebServlet(name="ServerTest", urlPatterns={"/ServerTest"})
public class ServerTest extends HttpServlet {
  protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // Checking request header
    if ("Dummy Protocol".equals(request.getHeader("Upgrade"))){
    ...
    ProtocolUpgradeHandler handler = request.upgrade(ProtocolUpgradeHandler.class);
    } else {
      response.setStatus(400);
      ...
    }
  }
  ...
}
ProtocolUpgradeHandlerは、HttpUpgradeHandlerの実装であり、アップグレード要求を処理し、通信プロトコルを切り替えます。サーバはアップグレードヘッダの値をチェックし、そのプロトコルをサポートしているかどうかを判断します。サーバーがリクエストをを受け入れると、101(Switching Protocols)レスポンス中のUpgradeヘッダフィールドを使ってどのプロトコルに切り替わったかを示す必要があります。

Implementation of HttpUpgradeHandler

public class ProtocolUpgradeHandler implements HttpUpgradeHandler {
  @Override
  public void init(WebConnection wc) {
    this.wc = wc;
    try {
      ServletOutputStream output = wc.getOutputStream();
      ServletInputStream input = wc.getInputStream();
      Calendar calendar = Calendar.getInstance();
      DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");

      // Reading the data into byte array
      input.read(echoData);

      // Setting new protocol header
      String resStr = "Dummy Protocol/1.0 " + CRLF;
      resStr += "Server: Glassfish/ServerTest" + CRLF;
      resStr += "Content-Type: text/html" + CRLF;
      resStr += "Connection: Upgrade" + CRLF;
      resStr += "Date: " + dateFormat.format(calendar.getTime()) +CRLF;
      resStr += CRLF;

      // Appending data with new protocol
      resStr += new String(echoData) + CRLF;

      // Sending back to client
      ...
      output.write(resStr.getBytes());
      output.flush();
    } catch (IOException ex) {
      Logger.getLogger(ProtocolUpgradeHandler.class.getName()).log(Level.SEVERE, null, ex);
    }
    ...
  }

  @Override
  public void destroy() {
    ...
    try {
      wc.close();
    } catch (Exception ex) {
      Logger.getLogger(ProtocolUpgradeHandler.class.getName()).log(Level.SEVERE, "Failed to close connection", ex);
    }
    ...
  }
}
init()メソッドは、新しいプロトコル・ヘッダを設定します。新しいプロトコルはその後の通信に使用されます。この例では、ダミーのプロトコルを使用しています。アップグレードプロセスが完了すると、destroy()メソッドが呼び出されます。この例では、プロトコルのアップグレードのハンドシェイクプロセスを示しています。ハンドシェイクプロセスが終わると、後続の通信は、新しいプロトコルを使用します。このメカニズムは、既存のトランスポート層の接続上のアプリケーション層プロトコルのアップグレードにのみ適用されます。この機能は、Java EEプラットフォームプロバイダにとって最も有用です。

2 Non-blocking IO

2.1 Description


Webコンテナでのノンブロッキングリクエスト処理はWebコンテナのスケーラビリティ改善に対する増大する要望への改善策であり、Webコンテナが同時に処理可能な接続数を増やすことができます。ServletContainerでノンブロッキングIOを使うと、開発者はデータが読み取り可能になった時点、書き込み可能になった時点で操作できるようになります。ノンブロッキングIOはServletとFilter、アップグレード処理における非同期リクエスト処理でのみ利用可能です。それ以外の場合、ServletInputStreamのsetReadListenerを呼び出した場合にはIllegalStateExceptionがスローされなければなりません。

2.2 Non-Blocking Read Example

Servlet


ServerServletでは、サーバがリクエストを受け取り、リクエストの非同期処理を開始して、ReadListenerを登録しています。
@WebServlet(name = "ServerServlet", urlPatterns = {"/server"}, asyncSupported = true)
 public class ServerServlet extends HttpServlet {
      .....
   protected void service(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    // async read
    final AsyncContext context = request.startAsync();
    final ServletInputStream input = request.getInputStream();
    final ServletOutputStream output = response.getOutputStream();
    input.setReadListener(new ReadListenerImpl(input, output, context));
   }
Note:
ノンブロッキングIOは、ServletおよびFilter、もしくはハンドラのアップグレードにおける非同期リクエスト処理でのみ利用できます。詳しくは、Servlet 3.1の仕様をご覧ください。

[訳注]
原文にはServlet Spec 3.2とありますが、Servlet 3.1の仕様としています。


Read Listener Implementation

public class ReadListenerImpl implements ReadListener {

  private ServletInputStream input;
  private ServletOutputStream output;
  private AsyncContext context;
  private StringBuilder sb = new StringBuilder();

  public ReadListenerImpl(ServletInputStream input, ServletOutputStream output, AsyncContext context) {
    this.input = input;
    this.output = output;
    this.context = context;
  }

  /**
   * do when data is available to be read.
   */
  @Override
  public void onDataAvailable() throws IOException {
    while (input.isReady()) {
      sb.append((char) input.read());
    }
  }

  /**
   * do when all the data has been read.
   */
  @Override
  public void onAllDataRead() throws IOException {
    try {
      output.println("ServerServlet has received '" + sb.toString() + "'.");
      output.flush();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      context.complete();
    }
  }

  /**
   * do when error occurs.
   */
  @Override
  public void onError(Throwable t) {
    context.complete();
    t.printStackTrace();
  }
データが入力リクエストストリームから読み込み可能になると、onDataAvailable()メソッドを呼び出します。コンテナはその後、isReady()からtrueが返ってくる場合に限り、read()メソッドを呼び出します。リクエストのすべてのデータが読み込まれたときに、onAllDataRead()メソッドを呼び出します。 onError(Throwable t)メソッドは、リクエストの処理中にエラーや例外が発生する場合に呼び出されます。基礎となるデータストリームがブロックされていない場合、isReady()メソッドはtrueを返します。この時点で、コンテナはonDataAvailable()メソッドを呼び出します。
ユーザーは、異なるパラメータを処理するようにコンストラクタをカスタマイズすることができます。通常、パラメータはServletInputStream、ServletOutputStream、あるいはAsyncContextです。このサンプルでは、それらのすべてを使用して、ReadListenerインタフェースを実装しています。

2.3 Non-Blocking Write Example

Servlet


ServerServlet.javaでは、リクエストを受け取った後にServletが非同期リクエスト処理を開始し、WriteListenerを登録します。
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    // async write
    final AsyncContext context = request.startAsync();
    final ServletOutputStream output = response.getOutputStream();
    output.setWriteListener(new WriteListenerImpl(output, context));
  }
Write Listener Implementation
public class WriteListenerImpl implements WriteListener {

  private ServletOutputStream output;
  private AsyncContext context;

  public WriteListenerImpl(ServletOutputStream output, AsyncContext context) {
    this.context = context;
    this.output = output;
  }

  /**
   * do when the data is available to be written
   */
  @Override
  public void onWritePossible() throws IOException {

    if (output.isReady()) {
      output.println("<p>Server is sending back 5 hello...</p>");
      output.flush();
    }

    for (int i = 1; i <= 5 && output.isReady(); i++) {
      output.println("<p>Hello " + i + ".</p>");
      output.println("<p>Sleep 3 seconds simulating data blocking.<p>");
      output.flush();

      // sleep on purpose
      try {
        Thread.sleep(3000);
      } catch (InterruptedException e) {
        // ignore
      }
    }
    output.println("<p>Sending completes.</p>");
    output.flush();
    context.complete();
  }

  /**
   * do when error occurs.
   */
  @Override
  public void onError(Throwable t) {
    context.complete();
    t.printStackTrace();
  }
}
データがレスポンスストリームに書き込めるようになると、onWritePossible()メソッドを呼び出しています。コンテナはその後、isReady()の結果がtrueである場合のみ、writeBytes()メソッドを呼び出します。レスポンスに書き込む間に何らかのエラーや例外が発生した場合には、onError(Throwable t)メソッドを呼び出します。基礎となるデータストリームがブロックされていない場合にisReady()メソッドはtrueを返します。この時点で、コンテナはwriteBytes()メソッドを呼び出します。

3 SessionID change

3.1 Description

Servlet 3.1仕様にはセッションの固定化を防ぐための新しいインターフェースやメソッドが導入されています。WebLogic ServerのServletContainerはセキュリティ上の理由で、セッションID変更処理が実装されています。

3.2 SessionID change Example

このサンプルアプリケーションでは、。SessionIDChangeListenerインターフェースがsessionIdChangedメソッドをオーバーライドしています。このメソッドはセッションのセッションIDの変更通知を受け取ります。SessionIDChangeTestは、javax.servlet.http.HttpServletRequest.changeSessionId()を呼び出してセッションIDの値を変更します。

Servlet

@WebServlet(name = "SessionIDChangeServlet", urlPatterns = {"/SessionIDChangeServlet"})
public class SessionIDChangeServlet extends HttpServlet {

  protected void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    HttpSession session = request.getSession(true);

    try {

      StringBuilder sb = new StringBuilder();

      sb.append("<h3>Servlet SessionIDChangeTest at " + request.getContextPath() + "</h3><br/>");
      sb.append("<p>The current session id is: &nbsp;&nbsp;" + session.getId() + "</p>");

      /* Call changeSessionID() method. */
      request.changeSessionId();

      sb.append("<p>The current session id has been changed, now it is: &nbsp;&nbsp;" + session.getId() + "</p>");

      request.setAttribute("message", sb.toString());
      request.getRequestDispatcher("response.jsp").forward(request, response);

    } finally {
      out.close();
    }
  }
....
}


Servletはリクエストからセッションオブジェクトを取得します。sessionIDはそのタイミングで生成されます。request.changeSessionId()が呼び出された後、新たなsessionIDが生成され、セッションオブジェクトの古いsessionIDに置き換わります。

HttpSessionIdListener Implementation
@WebListener
public class SessionIDChangeListener implements HttpSessionIdListener {

  @Override
  public void sessionIdChanged(HttpSessionEvent event, String oldSessionId) {
    System.out.println("[Servlet session-id-change example] Session ID " + oldSessionId + " has been changed");
  }
}
request.changeSessionId()が呼び出されると、実装されているsessionIdChangedメソッドが起動します。

[WLS, FMW] ZDT Technical Topic: How are Those Sessions Kept Alive Anyway?

原文はこちら。
https://blogs.oracle.com/WebLogicServer/entry/zdt_technical_topic_how_are

ローリング方式でWebLogicドメインのアップデートをする上で、Zero Downtime Patchingが便利に自動化する方法を提供しており、その内容に関するドキュメントやこれまでのブログエントリをこれまでにご覧になっていることと思います。プロセスを自動化することで、Zero Downtime Patchingが大幅に時間を節約し、手順を繰り返し実施することで潜在的に有するヒューマンエラーを排除します。それに加えて、ロールアウトプロセス中の任意の時点において、エンドユーザーのセッションを確実に失わないようにするHTTPセッションレプリケーション関連で特別な機能があります。Zero Downtime Patching実行中のセッション状態の維持について、技術的な詳細を探ってみましょう。

WebLogic Serverのセッション管理コントラクト(session persistence contract)の複製に関する重要な側面の一つとして、サーバがクラッシュするというまれな場合でもクラスタ内でセッションを維持することができる、というものです。しかし、複数のサーバが短時間の間にダウンした場合、セッション管理コントラクトはセッションの維持を保証できません。これは、セッションは1個のコピーを持ち、そのコピーをクラスタ内のセカンダリサーバに複製しているからです。セッションはクライアントがセッションを更新するリクエストを送信した場合以下の場合にのみ複製され、クライアントのCookieがセカンダリサーバへの参照を格納することができます。そのため、プライマリサーバがダウンして、後続のクライアントからのリクエストがセッションをアップデートするまでにセカンダリサーバが落ちる場合、セッションが失われるでしょう。Zero Downtime Patchingのローリングの性質はこのパターンに適合しており、それゆえにセッション消失を防ぐよう細心の注意を取る必要があります。
クラスタで一度に1台のサーバを再起動すれば非常に簡単にセッションを消失できることは、管理者の方であればすでにご存知のことと思います。

Zero Downtime Patchingによる、セッション消失の問題を防ぐ方法についての技術的な詳細に入る前に、この方法論は全体として、ロードバランシング、動的検出、ヘルスチェック、およびセッションフェイルオーバー処理を担保するOracle Traffic Directorに依存していることに注意することが重要です。この設定に加えて、セッションの損失を防ぐため、Zero Downtime Patchingが直接3個の主要な機能を使っています。

Session Handling Overview

1. Preemptive Session Replication

セッションデータは、正常なシャットダウン中、必要に応じて先んじてクラスタ内の別のサーバに伝播されます。より詳細に知りたい場合、ZDTロールアウトでHTTPセッションを保持しているサーバを停止し、続いて複製を保持するサーバを停止する、というシナリオを調べることができます。この場合、WebLogic Serverはシャットダウン中に、クラスタ内のバックアップ・コピーが存在しないため、セッションが失われることを検出することができます。そのため、ZDTロールアウトは、WebLogic Serverがクラスタ内の別のサーバにそのセッションを複製することを保証できるのです。

下図は、セッションの1次コピーを保持しているサーバS1が、2次またはレプリカコピーを保持するサーバS2のシャットダウンに引き続いて、シャットダウンするという問題のシナリオを示したものです。ZDTオーケストレーションがs2が停止する前に任意の1個のセッションのコピーを複製する必要がありことを通知します。そのため、常にクラスタ内に利用可能なセッションのコピーが存在するのです。

Preemptive Session Replication on Shutdown

2. Session State Query Protocol

WebLogic ServerがプライマリサーバとセカンダリサーバとのHTTPセッションの関連性に依存する方法が原因で、クラスタ内のどこかに、セッションを持つだけでは十分ではありません。クライアントのリクエストがクラスタ内の任意のサーバに到着すると、セッションを見つけることができる必要もあります。ZDTロールアウトを使うと、セッションのコピーを持っていない場合にクラスタ内の別のサーバに対し、特定のセッションを照会するためのWebLogic Serverの機能を有効にします。

Session Fetching via Session State Protocol Query

上図は、セッションのないサーバーへの着信リクエストがクエリを呼び出すことができ、セッションがクラスタ内で発見される場合には、セッションを読み取り、リクエストをサーバs4に提供することができる様子を示しています。

3. Orphaned Session Cleanup

セッション・インスタンスを先んじて複製する機能と、クラスタ内からセッションを取得する機能を組み合わせた後に、読み取ったインスタンスを積極的にクリーンアップするアプローチを取る必要もあります。歴史的には、WebLogic Serverは、孤立したセッションについて多くを心配する必要はありませんでした。フロントエンドのロードバランサとWebサーバには、セッションのサーバ・アフィニティを尊重することが求​​められています。そして、リクエストがプライマリまたはセカンダリサーバのいずれでもないサーバに到着するというまれなケースでは、セッションを、プライマリサーバまたはセカンダリサーバから取得することになるでしょう。その上で、タイムアウトまたは他の定期的な間隔でクリーンアップされるべき孤立したセッションのコピーは忘れられることになるでしょう。これは、セッションへのポインタが変更されたために、実際に格納された参照が再度使われることがないことが想定されます。しかし、ZDTロールアウトでは、セッションをクラスタ内で発見し、セッションを保持しているサーバから読み取る必要がある、というシナリオを繰り返し提示します。セッション・インスタンスの数が急速に増殖する(すべてが同じセッションの様々なバージョンということもあり得ます)可能性があるだけでなく、クラスタからコピーを検索し、古くなったコピーを見つけてはならないのです。つまり、セッションの現時点での唯一のレプリカのみを見つける必要があります。

Orphaned Session Cleanup

上図はs4がセッションデータを読み取って着信リクエストに応答した後のクリーンアップ・アクションを示しています。s3へのクリーンアップリクエストを発行し、確実にクラスタ内に古くなったデータを消去するようにしています。

Summary:

ZDT Patchingの間、server1を停止することができ、任意の孤立したセッションのコピーがクライアントの知らないうちにserver2に伝播されることが期待できます。クライアントが別のリクエストを送信した場合、WebLogic Serverは、そのリクエストを処理し、クラスタを照会してセッションデータを探すことができるようになります。データを読み取りリクエストを処理するサーバで利用されます。孤立したコピーがクリーンアップされ、リクエストを処理するサーバは、レプリカを格納するのに好ましいセカンダリサーバを選択するプロセスを通ります。

Zero Downtime Patchingの詳細は、以下のドキュメントをご覧ください。
Oracle® Fusion Middleware Administering Zero Downtime Patching Workflows 12c (12.2.1)
Configuring and Monitoring Workflows
http://docs.oracle.com/middleware/1221/wls/WLZDT/configuring_patching.htm#WLZDT166

References

Oracle® Fusion Middleware Oracle WebLogic Serverクラスタの管理 12c (12.1.3)
HTTPセッション状態のレプリケーション
http://docs.oracle.com/cd/E57014_01/wls/CLUST/failover.htm#i1027876
Oracle® Fusion Middleware Administering Clusters for Oracle WebLogic Server 12c (12.2.1)
HTTP Session State Replication
http://docs.oracle.com/middleware/1221/wls/CLUST/failover.htm#CLUST206

[WLS, FMW] WebLogic Server 12.2.1のMultitenancyはUpper Stack製品群もサポートするのか?

ちょっと質問をいただきました。


WebLogic Server 12.2.1のMultitenanfcyは、ミドルウェア製品、例えばSOA SuiteやService Bus、ADF(Application Development Framework)をサポートするの?


結論から言うと、現時点ではサポートされません。
以下のようにドキュメントにも明記されています。
WebLogic Server MT Supports Only Java EE Applications
http://docs.oracle.com/middleware/1221/wls/WLSMT/concepts.htm#WLSMT1270

つまり、Java EE 7に準拠したアプリケーションサーバとして使ってね、ということです。
誤解しないでいただきたいのは、単にマルチテナントに対応していない、というだけで、これまで通りの構成でSOA SuiteやADFなどは動作しますし、もちろんサポートもされます。

将来はWebLogic Server上で動作するミドルウェア製品もWebLogic Server Multitenant上で動作することになるでしょうが、現時点(2016年1月21日)ではまだ対応していない、ということをご理解ください。