Comments
Description
Transcript
Managed Bean
Java EE 7 エッセンシャル・レシピ ⽇日本オラクル株式会社 Fusion Middleware 事業統轄本部 Java エバンジェリスト 寺⽥田 佳央 Java Day Tokyo 2015 2015年年4⽉月8⽇日 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | • 以下の事項は、弊社の⼀一般的な製品の⽅方向性に関する概要を説明するものです。 また、情報提供を唯⼀一の⽬目的とするものであり、いかなる契約にも組み込むこ とはできません。以下の事項は、マテリアルやコード、機能を提供することを コミットメント(確約)するものではないため、購買決定を⾏行行う際の判断材料料 になさらないで下さい。オラクル製品に関して記載されている機能の開発、リ リースおよび時期については、弊社の裁量量により決定されます。 OracleとJavaは、Oracle Corpora@on 及びその⼦子会社、関連会社の⽶米国及びその他の国における登録商標です。 ⽂文中の社名、商品名等は各社の商標または登録商標である場合があります。 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Oracle Confiden@al – 4 @torazuka さん作 今日の献立 1. はじめに 2. Managed Bean 3. Interceptor 4. Bean Validation 5. DI 6. CDI Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 5 @torazuka さん作 今日の献立 1. はじめに 2. Managed Bean 3. Interceptor 4. Bean Validation 5. DI 6. CDI Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 6 エンタープライズ Java の歴史 JPE 1.0 J2EE 1.2 J2EE 1.3 J2EE 1.4 Java EE 5 2006年5月 Java EE 6 2009年12月 Java EE 7 2013年5月 もうJ2EE は忘れてください。(>_<) Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | エッセンシャル・レシピ 問題 • 「問題」(何がしたいか) • 「解決」(解決方法) • 「解説」(具体的な説明) Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 8 Java EE 7 の機能概要 ビュー関連のテクノロジー ビジネス・ロジック実装テクノロジー 横断的に利用可能な テクノロジー データ永続化、データ連携関連テクノロジー Java EE 7 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 9 JPA 2.1 JMS 2.0 Servlet 3.1 JTA 1.2 JCA 1.7 Batch 1.0 JavaMail 1.5 Concurrency UOl for EE 1.0 DI 1.0 / CDI 1.1 / EJB 3.2 EL 3.0 Interceptors 1.2 JSON-‐P 1.0 JSF 2.2 Common AnnotaOon 1.2 JSP 2.3 /JSTL JAX-‐RS 2.0 Managed Bean 1.0 WebSocket 1.0 Bean ValidaOon 1.1 Java EE 7 の機能一覧 Java EE 7 ※ 青枠は Java EE 7 で新規追加された機能 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 10 一般的なアプリケーション開発構成 ビュー関連処理 ビジネス・ロジック データ・アクセス DB ロジック Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Queue 11 今日お話をする所 ‒ ロジック実装部 ビュー関連処理 ビジネス・ロジック データ・アクセス DB ロジック Queue 疎結合での実装が重要 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 12 ビジネス・ロジックの実装テクノロジー CDI EJB DI Bean Validation Interceptor Managed Bean Java Common Annotation JSR-346 JSR-345 JSR-330 JSR-349 JSR-318 JSR-316 JSR-250 ビジネス・ロジック Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 13 @torazuka さん作 今日の献立 1. はじめに 2. Managed Bean 3. Interceptor 4. Bean Validation 5. DI 6. CDI Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 14 ビジネス・ロジックの実装テクノロジー CDI EJB DI Bean Validation Interceptor Managed Bean Java Common Annotation JSR-346 JSR-345 JSR-330 JSR-349 JSR-318 JSR-316 JSR-250 ビジネス・ロジック Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 15 JSR-250 Common Annotation (EE環境) Resource PreDestroy RolesAllowed ManagedBean Priority Resources PostConstruct RunAs DeclareRoles PermitAll DenyAll DataSourceDefiniOon DataSourceDefiniOons ※ Web コンテナ、EJB コンテナがサポートする JSR-250 のアノテーション一覧 EE.6.29 Common Annotations for the JavaTM Platform 1.2 Requirements 上記はアプリケーション・クライアントコンテナは除く Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 16 JSR-316 Managed Bean JSF Managed Bean CDI EJB JSR-‐316 Managed Bean EE 環境で @ManagedBean はほぼ直接使いません Managed Bean の機能は上位で利用可能です Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 17 Managed Bean でできる事 リソースの参照 インスタンスの生成 インスタンスの破棄 Web コンテナ CDI コンテナ EJB コンテナ リソース アプリケーション・サーバ Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 18 Managed Bean 問題 #1 : リソース参照 • リソースを参照したい • • • • • • データ・ベース JMS (Queue, Topic) トランザクション ORB メール・セッション コンテキスト Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 19 JNDI によるルック・アップ? Ini@alContext ic = new Ini@alContext(); ManagedExecutorService managedExecSvc = (ManagedExecutorService ) ic.lookup (" java:comp/DefaultManagedExecutorService"); mangedExecSvc.submit(() -‐> System.out.println(“New Thread”)); 悪くはありませんが、Java EE 環境では好ましくありません Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 20 解決 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 21 @Resource アノテーションによるインジェクト @Resource(name = “concurrent/DefaultManagedExecutorService") ManagedExecutorService mangedExecSvc; public void foo(){ mangedExecSvc.submit(() -‐> System.out.println(“New Thread”)); } Java EE 環境では、@Resource でリソースを注入します Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 22 解説 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 23 JSR-250 Common Annotation javax.annota@on アノテーション @Resource 説明 JNDI 名で参照できるリソースを注入。 注入可能なリソース: データソース、JMS リソース、トランザクション、 ORB、メールセッション、コンテキスト。 ※ ただし、@Resource で指定するのは、JNDI 名による文字列なため、 実行するまで指定されたリソースが有効か否かわかりません。 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 24 Managed Bean 問題 #2:ライフサイクル管理 • インスタンス生成後 • インスタンス破棄前 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 25 初期化はコンストラクタ? public class Foo() { @Resource(name = “concurrent/DefaultManagedExecutorService") ManagedExecutorService mangedExecSvc; public Foo(){ mangedExecSvc.submit(() -‐> System.out.println(“Init something”)); } } java.lang.NullPointerExcepOon 発生 コンストラクタの呼び出し時は リソース注入・依存性注入 が完了していません Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 26 解決 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 27 EE 環境では @PostConstruct で初期化 public class Foo() { @Resource(name = “concurrent/DefaultManagedExecutorService") ManagedExecutorService mangedExecSvc; @PostConstruct public void init (){ mangedExecSvc.submit(() -‐> System.out.println(“Init something”)); } } @PostConstruct は全てのインジェクションが完了後に実行 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 28 解説 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 29 JSR-250 Common Annotation javax.annota@on アノテーション @PostConstruct 説明 @PreDestroy コンテナによってインスタンスが破棄される前の処理、 リソースの解放などを実装 コンストラクタ呼び出し後、全てのインジェクション が完了した後の初期化処理を実装 ※ CDI や EJB などは、Proxy オブジェクトの為、オリジナルのクラスの コンストラクタとProxy のコンストラクタの両方(2回) 呼び出される 可能性があります。 参考:Why is the constructor invoked twice when a normal scoped bean is created? http://www.cdi-spec.org/faq/#accordion7 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 30 Managed Bean でできる事のまとめ : @Resource リソースの参照 インスタンスの生成 : @PostConstruct インスタンスの破棄 : @PreDestroy Web コンテナ CDI コンテナ EJB コンテナ リソース アプリケーション・サーバ Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 31 @torazuka さん作 今日の献立 1. はじめに 2. Managed Bean 3. Interceptor 4. Bean Validation 5. DI 6. CDI Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 32 ビジネス・ロジックの実装テクノロジー CDI EJB DI Bean Validation Interceptor Managed Bean Java Common Annotation JSR-346 JSR-345 JSR-330 JSR-349 JSR-318 JSR-316 JSR-250 ビジネス・ロジック Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 33 Interceptor : 横断的な関心事の実装 処理 A 処理 B 処理 C 処理 D 処理 E ログ出力、処理時間の計測、セキュリティ検査など Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 34 Interceptor の歴史 Java EE 5 (EJB 3.0) @AroundInvoke @Intercerptors @ExcludeDefaultInterceptors @ExcludeClassInterceptors EJB にのみ適用可能 Java EE 6 (EJB 3.1) ß CDI でも利用可能に @InterceptorBinding @Interceptor @AroundTimeout Java EE 7 (EJB 3.1 : Maintenance Release) Interceptor.Priority @AroundConstruct 任意の Bean に適用 XML の設定要 XML の設定不要 コンストラクタも可 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 35 Interceptor 問題 #3 横断的関心事分離 • 横断的な関心事を分離したい • ログ出力 • プロファイル • 監査 • セキュリティ・チェック Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 36 ロジック以外の内容も直接記述 ? public void executeSomeMethod1 () { long start = System.currentTimeMillis(); // 実行前の時間を取得 // ビジネス・ロジックの実装 long end = System.currentTimeMillis(); // 実行後の時間を取得 long Ome = end -‐ start; logger.log(Level.DEBUG, メソッド実行時間(ms) : + Ome); } ビジネス・ロジック以外の処理を存在、保守性の低下 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 37 解決 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 38 アノテーションで追加処理を実装 public class SomeLogic { @MySimpleProfilerInterceptor public void executeSomeMethod1 () { // ビジネス・ロジックの実装 } } ビジネス・ロジック以外の処理を分離 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 39 解説 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 40 Java EE 7 : 最新の Interceptor 実装方法 1. Interceptor 用のアノテーションを定義 2. Interceptor の実装コードの作成 3. 作成した Interceptor を利用 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 41 1. 汎用的に利用するためのアノテーションを定義 @Inherited @InterceptorBinding @Target({ElementType.TYPE, ElementType.METHOD}) @Reten@on([email protected]) public @interface MySimpleProfilerInterceptor { } @InterceptorBinding を使用した新規アノテーションを定義 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 42 2. Interceptor の実装コード @Priority(Interceptor.Priority.APPLICATION + 10) @MySimpleProfilerInterceptor //先ほど定義したアノテーション @Interceptor public class MyInterceptor { @AroundInvoke public Object calcExecTime (InvocaOonContext ic) throws Excep@on { //この部分に実装コードを記述 } Java EE 7 より @Priority の記述で beans.xml の設定は不要 } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 43 @AroundInvoke public Object calcExecTime (InvocaOonContext ic) throws ExcepOon { long start = System.currentTimeMillis(); // 実行前の時間を取得 try { return ic.proceed(); //オリジナルの呼び出し 実行前後の時間 } catch (Excep@on e) { を取得 throw e; } finally { long end = System.currentTimeMillis(); // 実行後の時間を取得 long Ome = end -‐ start ; 差分比較 String className = ic.getTarget().getClass().getSuperclass().getName(); String methodName = ic.getMethod().getName() ; logger.log(Level.INFO, "{0}#{1} took {2} (ms)", new Object[]{ className, methodName, Ome }); } ログ出力部分 } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 44 3. 作成した Interceptor を利用 @MySimpleProfilerInterceptor //自分で作成したインターセプタ public void executeSomeMethod() { // do Something } ログの出力例 情報: jp.co.oracle.cdis.HomePage#executeSomeMethod took 300 (ms) クラス・レベル or メソッド・レベルで指定可能 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 45 Interceptor : 横断的な関心事の実装 処理 A 処理 B @MyInteceptor 処理 C @MyInteceptor 処理 D @MyInteceptor 処理 E @MyInteceptor @MyIntecepto ログ出力、処理時間の計測、セキュリティ検査など Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 46 @torazuka さん作 今日の献立 1. はじめに 2. Managed Bean 3. Interceptor 4. Bean Validation 5. DI 6. CDI Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 47 ビジネス・ロジックの実装テクノロジー CDI EJB DI Bean Validation Interceptor Managed Bean Java Common Annotation JSR-346 JSR-345 JSR-330 JSR-349 JSR-318 JSR-316 JSR-250 ビジネス・ロジック Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 48 実装レイヤー毎にデータ検証の実装が必要 ビュー関連処理 ビジネス・ロジック データ・アクセス DB 検証 ロジック Queue 検証 検証 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 49 Bean Validation 問題 #4: 値の検証 • 宣言的な値の検証 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 50 個別に検証ロジッックを実装? public class Person { private String name; private String jpZipCode; public String doSomething() { if (name == null || name.equals("")) { validaOonFailed();}; if (jpZipCode == null || jpZipCode.equals("")) { validaOonFailed();}; Pajern pajern = Pajern.compile("^\\d{3}-‐\\d{4}$"); Matcher matcher = pajern.matcher(jpZipCode); if (!matcher.find()){validaOonFailed();} // ロジックの実装 }} Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 51 public class Person { private String name; private String jpZipCode; public String doSomething() { if (name == null || name.equals("")) { validaOonFailed();}; if (jpZipCode == null || jpZipCode.equals("")) { validaOonFailed();}; Pajern pajern = Pajern.compile("^\\d{3}-‐\\d{4}$"); Matcher matcher = pajern.matcher(jpZipCode); if (!matcher.find()){validaOonFailed();} // ロジックの実装 } } 冗長的、エラー内容は同じ 可読性の低下 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 52 解決 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 53 Bean Validation による検証 public class Person { @NotNull @Size(min=1) private String name; @NotNull @Size(min=8,max=8) @Pajern("^\\d{3}-‐\\d{4}$") private String jpZipCode; public String doSomething() { //ビジネス・ロジックの実装 宣言的にデータ検証 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 54 @torazuka さん作 今日の献立 1. はじめに 2. Managed Bean 3. Interceptor 4. Bean Validation 5. DI 6. CDI Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 55 ビジネス・ロジックの実装テクノロジー CDI EJB DI Bean Validation Interceptor Managed Bean Java Common Annotation JSR-346 JSR-345 JSR-330 JSR-349 JSR-318 JSR-316 JSR-250 ビジネス・ロジック Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 56 依存するクラスのインスタンス生成は ? ビジネス・ロジック ビュー関連処理 データ・アクセス DB ロジック new? Queue Factory? Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 57 JSR-330 : Dependency Injection for Java javax.inject パッケージ @Inject @Qualifier @Named @Scope @Singleton この2つはとても重要 限定的に利用 この2つはEE環境では ほぼ使わない Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 58 Dependency Injection 問題 #5:依存性注入 • 実装を疎結合で実装 • 型安全 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 59 CSV ファイルからデータ取得 public class PersonDAOFromCSV implements PersonDAO { public List<Person> getPersons() throws IOExcepOon{ FileSystem fs = FileSystems.getDefault(); Path file = fs.getPath("/tmp/listPerson.csv"); return Files.newBufferedReader(file).lines().map(str -‐> { String[] array = str.split(","); Person person = new Person(); person.setName(array[0]); person.setAge(Integer.parseInt(array[1])); return person; }).collect(Collectors.toList()); } } CSV ファイルから List<Person> を取得 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 60 ファイルからデータ取得、DBは駄目? public class PersonController { public void listPersonName() throws IOExcep@on { // ある Person のDAOからデータ取得 PersonDAO personDAO = new PersonDAOFromCSV(); List<Person> persons = personDAO.getPersons(); persons.forEach(person -‐> System.out.println(person.getName())); } } new→Factory→Abstract Factory→Service Locator Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 61 解決 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 62 依存性注入で疎結合,テストも用意, モック作成!! public class PersonController { @Inject PersonDAO personDAO ; //依存性を注入 public void listPersonName() throws IOExcep@on { List<Person> persons = personDAO.getPersons(); persons.forEach(person -‐> System.out.println(person.getName())); } } new -‐> Factory -‐> Abstract Factory -‐> Service Locator デザイン・パターンの適用より柔軟・簡単 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 63 解説 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 64 new と @Inject の違い 密結合 PersonController 疎結合 PersonDAO new PersonDAO() PersonController @Inject PersonDAO PersonDAO dao.getPersons() dao.getPersons() DI コンテナ PersonDAO インスタンス生成 PersonDAO をインジェクト PersonDAO の機能を利用 コンテナがインスタンス生成 PersonDAO の機能を利用 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 65 Dependency Injection 問題 #6:対象の限定 • 複数の実装から特定の実装 を選択したい Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 66 複数の実装クラスがあります public interface Service { public void doSomething (); } public class DukeService implements Service { @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duke Service”); } } public class DuchessService implements Service { @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duchess Service”); } } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 67 どのサービスにインジェクト? public class Foo { @Inject private Service service; public void execService(){ service.doSomething(); } } OR Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | ??? 68 解決 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 69 限定子(Qualifier)を指定しましょう @Inject @DukeQualifier Service service1; public void execMul@pleService(){ service1.doSomething(); } @Inject @DuchessQualifier Service service2; public void execMul@pleService(){ service2.doSomething(); } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 70 解説 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 71 Qualifier : 限定子の作り方 1新規限定子 (@Qualifier) を定義 2実装クラスの作成 3Qualifier の実装クラスを選択 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 72 1新規限定子 (@Qualifier) を定義 @Dependent @Qualifier @Reten@on([email protected]) @Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) public @interface DukeQualifier {} 特定の実装に限定するための限定子を作成 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 73 2実装クラスを作成 @DukeQualifier public class DukeServiceImpl implements Service { @Override public void doSomething() { System.out.println("Duke Service"); } } 限定子を指定した実装側を作成 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 74 3Qualifier の実装クラスを選択 @Inject @DukeQualifier Service service1; public void execMul@pleService(){ service1.doSomething(); } インジェクト時に限定子を付加し、対象を限定 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 75 Qualifier 作成時の注意点 限定子 (Qualifier) アノテーションを作成する場合、 限定子と分かるパッケージング/名前をつけましょう。 例: com.yoshio3.qualifiers.* @DukeQualifier, @DatabaseQualifier 独自生成した他のアノテーションとの混同をさけるため Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 76 Dependency Injection 問題 #7:不変オブジェクト • イミュータブル(不変な) オブジェクトとしてインス タンスを生成したい Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 77 Duke サービスが実装されています @Dependent public interface Service { 限定子 : @Qualifier @Qualifier public void doSomething (); } インタフェース @Reten@on([email protected]) @Target({ElementType.FIELD, @DukeQualifier ElementType.TYPE, public class DukeService implements ElementType.METHOD, Service{ ElementType.PARAMETER}) @Override public @interface DukeQualifier { public void doSomething () { } // 何らかの処理理 System.out.println(“Duke Service”); } 先ほどのと同じコード 実装クラスの作成 } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 78 Duke サービスを変更できないように する場合どうしましょう? Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 79 final なフィールドにインジェクト? public class Foo { @Inject @DukeQualifier private final Service service; public void execService(){ service.doSomething(); } } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 80 解決 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 81 コンストラクタでインジェクト @Dependent public class Foo { private final Service service; @Inject public Foo(@DukeQualifier Service service) { this.service = service; } public void execService(){ service.doSomething(); コンストラクタで、インジェクトし final な変数に代入で不変オブジェクト }} を生成可能 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 82 解説 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 83 インジェクト・ポイントの選択 ●フィールド・セッタメソッドに対するインジェクト: 利点:インジェクションが簡単 欠点:オブジェクトがミュータブル(変更可能)になる ●コンストラクタに対するインジェクト: 利点:オブジェクトをイミュータブル(不変)にする事が可能 テストが容易になる 欠点:フィールドが複数ある場合、コンストラクタ引数も多数必要 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 84 Dependency Injection 問題 #8 文字で対象選択 • 文字列を指定しインジェク ト先を限定したい Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 85 たくさんの実装サービスがある場合は? public interface Service { public void doSomething (); } @Duchess @Duke @Printer @Foo @MyEnterprise @GlassFish @IoT @Oracle @Bar @Hoge @MySQL たくさんの限定子を作成 ?! Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 86 解決 ?! Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 87 @Named で名前を付けてひも付けできます public interface Service { public void doSomething (); } @Named(value=“duke”) public class DukeService implements Service{ @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duke Service”); } } ここまでは OK です!! Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 88 でも !! ひも付けした物の利用は? public interface Service { public void doSomething (); } @Named(value=“duke”) public class DukeService implements Service{ @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duke Service”); } } @Inject @Named(value=“duke”) Service service1; public void execMul@pleService(){ service1.doSomething(); } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 89 この方法はお勧めしません!! Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 90 解説 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 91 警告もしくはデプロイ・エラー(Weld) public interface Service { public void doSomething (); } @Named(value=“duke”) public class DukeService implements Service{ @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duke Service”); } } @Inject @Named(value=“duke”) Service service1; public void execMul@pleService(){ service1.doSomething(); } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 92 DI ではなく CDI 側の仕様確認 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 93 文字列でひも付けはお勧めしません。 JSF(EL 式) など特定目的にのみご利用ください。 極力 DI は型に対して行うのが基本 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 94 @torazuka さん作 今日の献立 1. はじめに 2. Managed Bean 3. Interceptor 4. Bean Validation 5. DI 6. CDI Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 95 ビジネス・ロジックの実装テクノロジー CDI EJB DI Bean Validation Interceptor Managed Bean Java Common Annotation JSR-346 JSR-345 JSR-330 JSR-349 JSR-318 JSR-316 JSR-250 ビジネス・ロジック Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 96 Java EE インジェクションの復習 • リソースのインジェクション @Resource Managed Bean • 依存性のインジェクション @Inject @EJB Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | DI/CDI EJB 97 CDI と EJB の違い (Out of Scope) CDI EJB 16:15-‐ 17:05 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 98 JSR-346 : Contexts and Dependency Injection for Java™ EE 1.2 • • • • • javax.decorator javax.enterprise.context javax.enterprise.event javax.enterprise.inject javax.enterprise.uOl Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 99 Java EE 環境用に CDI が提供する機能 CDI Managed Bean の有効化 型安全のインジェクション Java EE 環境に特化した スコープの提供 EL 式で名前によるインジェクション インターセプタ・デコレータ Observer パターンによるイベント処理 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 100 Contexts&Dependency Injection 問題 #9:CDI の有効化 • CDI を利用可能にしたい Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 101 CDI Managed Bean を利用するため Java EE 7 からデフォルトで有効です Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 102 全てを対象にするための設定 (Java EE 6互換) /WEB-INF/beans.xml を作成 <?xml version="1.0" encoding="UTF-‐8"?> <beans xmlns="hup://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="hup://www.w3.org/2001/XMLSchema-‐instance" xsi:schemaLoca@on="hup://xmlns.jcp.org/xml/ns/javaee hup://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" bean-‐discovery-‐mode="all"> </beans> It is strongly recommended you use "annotated” Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 103 CDI コンテナ起動時に全クラスをスキャン Java Class Java Class Java Class Java Class Java Class Java Class Java Class Java Class Java Class Java Class Java Class CDI Container 大量クラスのスキャンで起動時間の大幅遅延・参照も保持 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 104 解決 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 105 CDI アノテーションを付加した物のみ DI 対象 CDI Managed Bean として自動認識可能な Bean • @NormalScope を継承したスコープ • • • • @ApplicaOonScoped @SessionScoped @ConversaOonScoped @RequestScoped • その他 (継承して独自に定義) • • • • @Dependent (凝似スコープ) @Interceptor @Decorator @Stereotype で独自に作成 エラー: UnsaOsfied dependencies for type NGClass with qualifiers @Default 条件を満たさない場合 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 106 解説 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 107 CDI Managed Bean とは ? Contextual Reference 実装クラス 実装クラス 実装クラス コンテナがProxy を生成 CDI Container コンテキスト情報を持つコンテナ管理のインスタンス Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 108 @Inject オリジナル・インスタンスではなく Proxy @Inject SomeManagedBean bean; 実装クラス Contextual Reference bean は実装クラスでなく Proxy のインスタンス 実装クラス プログラムの呼び出し側 CDI Container Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | Proxy 109 CDI Managed Bean (Proxy) の持つ情報 javax.enterprise.inject.spi.Bean 含まれる情報 説明 Qualifiers Scope Stereotypes Type AlternaOve 限定子の一覧 (Set) 名前 省略可能: @Namedで使用する名前 Bean のスコープ ステレオタイプの一覧 (Set) Bean の型情報の一覧 (Set) Bean が Alternative か否か CDI Managed Bean が持つ属性情報 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 110 Java EE / Web Container では下記の情報も持つ Contextual Reference CDI Managed Bean Bean Proxy UserTransacOon Principal Validator ValidatorFactory HjpServletRequest HjpSession ServletContext CDI Container Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 111 Contexts&Dependency Injection 問題 #10:有効範囲の設定 • スコープについて Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 112 Java EE 環境におけるスコープ • 凝似スコープ – DI : javax.inject.Scope • Singleton – CDI : javax.enterprise.context • Dependent • CDI ノーマル・スコープ – CDI : javax.enterprise.context. NormalScoped (全ての基本) • ApplicationScoped • SessionScoped • RequestScoped • ConversationScoped – JSF : javax.faces. スコープで利用範囲を規定 • view.ViewScoped • flow.FlowScoped Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 113 CDI のスコープについて ‒ JSF での利用例 15:10-‐ 16:00 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 114 Java EE 環境でのシングルトンの実装 質問:どちらで実装するのが正しいでしょうか? javax.inject.Singleton ? javax.enterprise.context.ApplicaOonScoped ? Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 115 @javax.inject.Singleton で実装 @javax.inject.Singleton public class DukeCounter { private int counter; public int getCounter() { return counter++; } } @Singleton は Managed Bean にならない Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 116 解決 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 117 Java EE 環境での正しいシングルトン @javax.enterprise.context.ApplicaOonScoped public class DukeCounter implements Serializable { private int counter; public int getCounter() { return counter++; } } ApplicationScoped を使いましょう!! Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 118 解説 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 119 javax.inject.Singlton はコンテキスト情報を持ちません Contextual Reference 実装クラス 実装クラス 実装クラス CDI Container 直接シングルトン・インスタンスの参照を保持 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 120 @Singleton は特定スコープで問題発生 @SessionScoped //もしくは @ConversaOonScoped public class CounterHoldInSession implements Serializable{ @Inject DukeCounter singleton; } Java EE 6 ではコンパイルに通るが問題発生の可能性あり (Singleton & Serializable) 最新版の Weld(CDI 参照実装) ではコンパイル・エラー Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 121 Contexts&Dependency Injection 問題 #11 : 唯一の選択 • • • • ロジックのバージョニング 実装の切替えを行いたい 配備時に切替え プログラミング時に切替え Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 122 サービスの実装バージョンが複数あります public interface Service { public void doSomething (); } public class DukeSvc implements Service { @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duke Service”); } } DukeAlpha DukeBeta DukeProd Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 123 テスト環境用の実装、本番環境用の実装 public interface DataAccessService { public List<Persion> getData (); } class テスト環境用 implements DataAccessService { @Override public List<Person> getData () { // テストDB からデータ取得 } } class 本番環境用 implements DataAccessService { @Override public List<Person> getData () { // 本番 DB からの実データ取得 } } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 124 どのようにして択一の「最新バージョン」 「本番環境バージョン」に切替えますか? Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 125 解決 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 126 @Alternative(択一)を利用します @Dependend @AlternaOve public class DukeAlpha implements Service{ } @Dependend @AlternaOve public class DukeBeta implements Service{ } Alternative を指定し、配備時にXMLで択一可能 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 127 解説 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 128 @Alternative(択一)の実装定義方法 @Dependend @AlternaOve public class DukeAlpha implements Service{ } @Dependend @AlternaOve public class DukeBeta implements Service{ } 注: annotatedの場合 CDI で管理するため@Dependentが必要 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 129 「配備時」に切り替えをしたい場合 (CDI 1.0) @Dependend @AlternaOve public class DukeAlpha implements Service{ } <beans> <alterna@ves> <class>DukeBeta</class> </alterna@ves> </beans> @Dependend @AlternaOve public class DukeBeta implements Service{ } beans.xml で対象を選択 同一のアーカイブに含まれている物 のみが対象 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 130 「開発時」に切り替えしたい場合(CDI 1.1) @Dependend @AlternaOve @Priority(Interceptor. Priority.APPLICATION + 10) public class DukeAlpha implements Service{ } @Dependend @AlternaOve @Priority(Interceptor. Priority.APPLICATION + 20) public class DukeBeta implements Service{ } プライオリティは 大きい数が優先 異なる、jar に含まれる物も対象 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 131 限定子がなくても DukeBeta が選択 @Inject Service service ; @Dependend @AlternaOve @Priority(Interceptor. Priority.APPLICATION + 20) public class DukeBeta implements Service{ } @Inject で限定子が付加されて なくても XML の設定に従い インジェクトが可能 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 132 しかし、ここで問題が一つ !! Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 133 限定子(Qualifier)が付加された場合 @Inject Service @DukeServiceQualifier service ; @DukeServiceQualifier public class DukeServiceWithQualifier implements Service { } @AlternaOve の設定は無効に !! Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 134 @Specialized で限定子を拡張可能(CDI 1.1) @Inject Service @DukeServiceQualifier service ; @DukeServiceQualifier @Specializes public class SpecializedDuke extends DukeServiceWithQualifier { @Override public void doSomething() { } } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 135 Contexts&Dependency Injection 問題 #12:柔軟な生産 • CDI Managed Bean でない クラスもインジェクトした い • 実行時に対象オブジェクト を変更したい Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 136 実行時に条件に基づき DB を変更したい ビジネス・ロジック データ・アクセス Oracle 本番環境 MySQL テスト環境 ロジック PostgreSQL Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 開発環境 137 今まで : EJB + JPA の永続ユニット設定 @Stateless @Stateless public class SomeLogic1 { PersitenceContext (unitName=“ORACLE_PU”) EnOtyManager em; @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duke Service”); } } public class SomeLogic2 { PersitenceContext (unitName=“MYSQL_PU”) EnOtyManager em; @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duke Service”); } } EJB EJB Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 138 JPA のユニット名は全て文字 文字の打ち間違えは? 大量に修正するのは困難 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 139 解決 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 140 @Produces の利用 ‒ 型による参照解決 @Inject @DatabaseQualifier(value= DatabaseList.Oracle) EnOtyManager em; @Inject @DatabaseQualifier(value= DatabaseList.MySQL) EnOtyManager em; 型でインジェクト Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 141 解説 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 142 @Produces の作り方 1選択子の列挙型(enum)の作成 2限定子(Qualifier)の作成 3@Produces の定義 4限定子を利用して動的に DB を選択 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 143 1選択子の列挙型(enum)の作成 public enum DatabaseList { Oracle, MySQL, PostgreSQL } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 144 2限定子 (Qualifier) の作成 @Dependent @Qualifier @Reten@on([email protected]) @Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) public @interface DatabaseQualifier { DatabaseList value() default DatabaseList.Oracle ; } 引数未指定時のデフォルト値も設定可能 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 145 3@Produces の定義 ‒ ここが重要 !! @Dependent public class DatabaseProducer { リソース生成はここで一元管理 !! メソッドで条件による生成も可能 !! @Produces @DatabaseQualifier(value = DatabaseList.Oracle) @PersistenceContext(unitName = "ORACLE_PU") private En@tyManager emOracle ; Oracle 本番環境 @Produces @DatabaseQualifier(value = DatabaseList.MySQL) @PersistenceContext(unitName = "MySQL_PU") private En@tyManager emMySQL; } MySQL Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | テスト環境 146 4限定子を利用して動的に DB を選択 @Dependent @TransacOonal public class SomeBusinessLogic { @Inject @DatabaseQualifier(value= DatabaseList.MySQL) EnOtyManager em; value は省略可能 未指定時はデフォルトの Oracle public List<Person> getPersons(){ em.createQuery(…..); } } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 147 Contexts&Dependency Injection 問題 #14 : アノテーションの整理 • 大規模開発むけ • 毎回大量のアノテーション を付加するのは面倒 • 複数のアノテーションをま とめたい Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 148 大量の同一アノテーションの指定は苦痛 !! @Named @RequestScope @SecurityChekIntercepter @LoggerIntercepter @TransacOonal @Named @Named @Named @RequestScope @RequestScope @RequestScope @SecurityChekInterce pter @SecurityChekInter cepter @SecurityChekInter cepter @LoggerIntercepter @LoggerIntercepter @LoggerIntercepter @TransacOonal @TransacOonal @TransacOonal public class public class public class UserRegPage { UserConfirmPage { UserComplPage { public class IndexPage { @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duke Service”); }} } } } 大規模開発では指定忘れも !! Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 149 解決 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 150 @Stereotype でまとめた物を利用します @MyReqestedScopeStereotype public class IndexPage { @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duke Service”); }} @MyRequestedScope Stereotype @MyRequestedScop eStereotype @MyRequestedScop eStereotype public class public class public class UserRegPage { UserConfirmPage { UserComplPage { } } } Proj 専用アノテーションを定義可能 指定のし忘れを軽減 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 151 解説 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 152 @Stereotype の作り方 @Named @RequestScope 複数のアノテーション指定を @SecurityChekIntercepter 1つのアノテーションでまとめる @LoggerIntercepter @TransacOonal @Stereotype @Target(TYPE) @Reten@on(RUNTIME) public @interface MyReqestedScopeStereotype {} Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 153 2つは同一の意味を持つ @Named @RequestScope @SecurityChekIntercepter @LoggerIntercepter @TransacOonal public class IndexPage { @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duke Service”); }} @MyReqestedScopeStereotype public class IndexPage { @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duke Service”); }} Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 154 組み込み @Stereotype : @Model @Named @ReauestScope public class IndexPage { @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duke Service”); }} @javax.enterprise.inject.Model public class IndexPage { @Override public void doSomething () { // 何らかの処理理 System.out.println(“Duke Service”); }} Web アプリケーション開発で、@Named, @RequestedScope の組み合わせは頻繁に利用 → @Model を作成 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 155 Stereotype 作成時の注意点 Stereotype を作成する場合、 Stereotype と分かるパッケージング/ 名前をつけましょう。 例: com.yoshio3.stereotypes.* @DukeStereotype, @DatabaseStereotype 限定子のアノテーションとの混同をさけるため Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 156 Contexts&Dependency Injection 問題 #13 : イベント処理 • Observer パターンの適用 • イベント処理を行いたい Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 157 Observer パターンを適用した イベント通知が可能 システム監視 特定の条件のみ実行 異常検知 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 158 CDI イベントの実装例 ‒ イベント通知側 @RequestScoped @Named(value = ”userReg") public class UserRegistra@onPage { @Inject Event<Mail> mailEvent; //任意のオブジェクトを指定可能 public void execUserRegistra@on() { //ユーザ登録処理理が完了了 mailEvent.fire(new Mail(mailaddredd, name, message)); } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 159 CDI イベントの実装例 ‒ イベント受信側 @Applica@onScoped public class MailEventHandler { @Resource(name = "mail/MyMailSession") Session mailSession; public void receiveEvent(@Observes Mail mailEvent) { sendMessage(mailEvent); } } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 160 簡単にイベント処理を実装できます !! しかしこのコードには問題があります。 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 161 受信側で「重い処理」をするのは NG @Applica@onScoped public class MailEventHandler { @Resource(name = "mail/MyMailSession") Session mailSession; public void receiveEvent(@Observes Mail mailEvent) { sendMessage(mailEvent); // 重い処理 } } CDI のイベント処理は同期処理 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 162 解決 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 163 重い処理は非同期 EJB もしくは JMS を利用 !! @Stateless public class MailEventDispatcherBean { @Inject Event<Mail> mailEvent; //任意のオブジェクトを指定可能 @Asynchronous public void produceEvent(final Mail message) { //ユーザ登録処理理が完了了 mailEvent.fire(message); 非同期でイベント送信 } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 164 重い処理は非同期 EJB もしくは JMS を利用 !! @javax.ejb.Singleton // ← javax.inject.Singleton ではない EJB public class EventConsumer { @Asynchronous @Lock(LockType.READ) public void consumeEvent(@Observes Mail message) throws InterruptedExcep@on { //何か重い処理理 } 非同期でイベント受信 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 165 重い処理は非同期 EJB もしくは JMS を利用 !! @RequestScoped @Named(value = ”userReg") public class UserRegistra@onPage { @EJB MailEventDispatcherBean dispather; public void execUserRegistra@on() { //ユーザ登録処理理が完了了 dispather.produceEvent(new Mail(mailaddredd, name, message)); } Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 166 解説 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 167 CDI の Event 処理は同期処理です 長時間処理は非同期実装をご検討ください CDI 2.0 では Asynchronous の検討中 (https://issues.jboss.org/browse/CDI-499) Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 168 今日の献立 さいごに @torazuka さん作 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 169 Managed Bean で実装するか否か? コンテナで管理されないオブジェクトでいい? • • • リソース参照が不要な場合 ライフサイクル管理が不要な場合 DI/CDI, EJB の機能が不要な場合 コンテナ管理 : Managed Bean → CDI → EJB 全てを Managed Bean にする必要は ありませんが十分に検討が必要 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 170 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 171 Copyright © 2015, Oracle and/or its affiliates. All rights reserved. | 172