***************************************************-->
このチュートリアルでは、Oracle JDeveloperとOracle Mobile Application Framework(Oracle MAF)を使用してSQLiteデータベースをインストールし、そのデータベースから値を表示するMAFアプリケーションを作成します。
詳細を表示/非表示詳細表示

このチュートリアルでは、MAFアプリケーションを作成し、デバイスのネットワーク・ステータスに応じてローカル・データベースまたはリモートのWebサービスからレコードを取得するようにそのアプリケーションを設定します。

左のイメージはWebサービスから取得したデータ、右のイメージはローカル・データベースから取得したデータです。

alt text alt text


前提条件:

このチュートリアルを実行するには、JDeveloper 12.1.3とOracle MAF拡張をインストールしておく必要があります。また、Android SDK 4.2.2 APIレベル17をインストールしておく必要もあります。お好みで、アプリケーションを接続中のAndroidデバイスにデプロイできます。このチュートリアルでは、Androidエミュレータへのアプリケーションのデプロイ方法を示します。エミュレータの起動には、Android Virtual Device(AVD)Managerを使用します。AVD ManagerはAndroid SDK Toolsに付属しています。

iOS環境を使用する場合は、次のチュートリアルを使用して開発環境を設定できます。iOS環境の設定と構成

Android環境を使用する場合は、次のチュートリアルを使用できます。Android環境の設定と構成

目的 時間 アプリケーション
このチュートリアルでは、Mobile Application FrameworkでSQLiteデータベースを使用したアプリケーションを開発する方法について説明します。このチュートリアルで作成するアプリケーションの完成版を確認するには、Downloadボタンをクリックして完成版アプリケーションのzipファイルをダウンロードし、JDeveloperのmyworkフォルダに解凍してください。 2時間 My First Application Solution.zipのダウンロード

パート1:SQLiteデータベースの初期化とデータ・アクセス・コードの書込み

この項では、Oracle Application Development Framework Mobile(Oracle ADF Mobile)アプリケーションを作成してから、ローカル・データベースを初期化してレコードを移入し、レコードを取得する段階になったら接続を確立するように構成します。

ステップ1:ApplicationControllerプロジェクトの設定とデータベースの初期化
  1. JDeveloper 12.1.3を開きます。

  2. アプリケーション・ナビゲータで「New Application」をクリックします。

    アプリケーション・ナビゲータ
  3. Mobile Application Framework Application」を選択します。「OK」をクリックします。

    New Gallery
  4. SummitLocalDBという名前を付け、「Finish」をクリックします。

  5. Create Mobile Appのステップ1
  6. アプリケーションの起動時にデータベースを初期化するように、LifecycleListenerImpl.javaを変更します。

    ApplicationController」→「Application Sources」→「Application」の順にノードを開き、「LifecycleListenerImp.java」をダブルクリックします。

  7. Create Mobile Appのステップ2
  8. startメソッドまで下にスクロールし、メソッドに次のコードを追加します。

    import oracle.adfmf.util.Utility;がクラスに追加されます。

    initializeDatabaseFromScriptメソッドはまだ定義されていないため、エラーとしてフラグが付きます。これは問題ではありません。簡単に修正できます。

  9. Create Mobile Appのステップ3
  10. deactivateメソッドの直後までスクロールし、次のコードを追加します。これは、デバイスのストレージからSQLスクリプトを1行に1つずつ読み込み、データベース・レコードを作成するコードです。

    コードを追加するとき、import oracle.adfmf.util.Utilityおよびjava.sql.Connectionと、他のクラスのすべてのデフォルトのimportが推奨されます。

    このコードは次のような処理を実行します。
    1:コードを追加するとき、import oracle.adfmf.util.Utilityおよびjava.sql.Connectionと、他のクラスのデフォルトのimportが推奨されます。
    2:ローカル・データベース・ファイルへのパスを取得します。
    3:dbファイルが存在するかどうかを確認します。
    4:存在しない場合は作成します。自動コミットは必ずオフにしてください。開いたときに存在しない場合は、dbファイルが作成されます。
    5:ストレージからdbスクリプトを取得し、メモリに格納します。
    6:スクリプトを1行ずつ繰り返します。remまたはcommentで始まる行はスキップし、それ以外の行は1行ずつ実行します。
    7:例外を処理します。


    public void deactivate()
    {
    }

        // 1:デバイスのストレージからSQLスクリプトを1行に1つずつ読み込み、データベース・レコードを作成する
            private void initializeDatabaseFromScript() throws Exception {
                InputStream scriptStream = null;
                Connection conn = null;
                try {
                   
            // 2:ローカル・データベース・ファイルへのパスを取得する          
                    Utility.ApplicationLogger.info("Initializing DB...");
                    String docRoot = AdfmfJavaUtilities.getDirectoryPathRoot(AdfmfJavaUtilities.ApplicationDirectory);
                    String dbName = docRoot + "/sm.db";
                   
            // 3:dbファイルが存在するかどうかを確認する
                    File dbFile = new File(dbName);
                    if (dbFile.exists())
                        return;
                   
            // 4:存在しない場合は作成する。自動コミットは必ずオフにすること。開いたときに存在しない場合は、dbファイルが作成される
                    conn = new JDBCDataSource("jdbc:sqlite:"+ dbName).getConnection();
                    conn.setAutoCommit(false);
                   
            //  5:ストレージからdbスクリプトを取得し、メモリに格納する
                    Utility.ApplicationLogger.info("Reading script");
                    scriptStream =
                        Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/initializedb.sql");
                    BufferedReader scriptReader = new BufferedReader(new InputStreamReader(scriptStream));
                    String nextLine;
                    StringBuffer nextStatement = new StringBuffer();
                   
            // 6:スクリプトを1行ずつ繰り返す。remまたはcommentで始まる行はスキップし、それ以外の行は1行ずつ実行する
                    Statement stmt = conn.createStatement();
                    while ((nextLine = scriptReader.readLine()) != null) {
                    if (nextLine.startsWith("REM") || nextLine.startsWith("COMMIT") || nextLine.length() <1)
                        continue;
                    nextStatement.append(nextLine);
                        if (nextLine.endsWith(";")) {
                            Utility.ApplicationLogger.info("Execute statement:" + nextStatement.toString());
                            stmt.execute(nextStatement.toString());
                            nextStatement = new StringBuffer();
                        }
                    }
                   
            // 7:例外処理
                        }finally {
                            if (conn != null) {
                                conn.commit();
                                conn.close();
                        }
            } 
          


  11. Create Mobile Appのステップ4
  12. 作業内容を保存します。

  13. 次に、Lifecycleイベント・リスナー・クラス(LifecycleListenerImpl.java)をアプリケーションに登録します。

    Application Resourcesペインで、「Descriptors」→「ADF META-INF」の順にノードを開き、「maf-application.xml」ファイルをダブルクリックします。

    Applicationタブに、Lifecycle Event Listenerのプロパティが表示されます。デフォルトの値はapplication.LifecycleListenerImplに設定されています。これは先ほど変更したファイルです。デフォルトのライフサイクル・リスナー・ファイルを使用しない場合は、この値を使用するファイルに設定する必要があります。

    値がapplication.LifecycleListenerImplに設定されていることを確認します。

  14. Create Mobile Appのステップ2


    Create Mobile Appのステップ2
ステップ2:データベース・レコードを作成するコードの追加

データベースを初期化するコードを追加したので、この項ではデータベース・レコードを作成するSQLコードを含むファイルを追加します。

  1. ApplicationControllerプロジェクトで、「META-INF」ディレクトリ(ここで初期化メソッドがSQLコードを検索します)を右クリックし、「New」→「From Gallery」を選択します。

  2. adfmf-feature.xml
  3. New Galleryで「General」カテゴリ→「File」項目の順に選択します。

    ファイルの名前としてinitializedb.sqlと入力し、「OK」をクリックします。

  4. Features表

    Features表
  5. データベースを初期化してレコードを追加する次のコードを追加します。

    すべての作業内容を保存します。


    PRAGMA foreign_keys = ON;
    PRAGMA auto_vacuum = FULL;
    CREATE TABLE REGIONS (REGION_ID NUMBER PRIMARY KEY, REGION_NAME VARCHAR2(25));
    CREATE TABLE COUNTRIES (COUNTRY_ID CHAR(2) PRIMARY KEY, COUNTRY_NAME VARCHAR2(40), REGION_ID NUMBER, FOREIGN KEY (REGION_ID) REFERENCES REGIONS(REGION_ID) );
    INSERT INTO REGIONS (REGION_ID,REGION_NAME) VALUES (1,'Europe');
    INSERT INTO REGIONS (REGION_ID,REGION_NAME) VALUES (2,'Americas');
    INSERT INTO REGIONS (REGION_ID,REGION_NAME) VALUES (3,'Asia');
    INSERT INTO REGIONS (REGION_ID,REGION_NAME) VALUES (4,'Middle East and Africa');
    INSERT INTO COUNTRIES (COUNTRY_ID, COUNTRY_NAME, REGION_ID) VALUES ('AD','ADFa', 1);
    INSERT INTO COUNTRIES (COUNTRY_ID, COUNTRY_NAME, REGION_ID) VALUES ('DU','United States of Duke', 2);
    INSERT INTO COUNTRIES (COUNTRY_ID, COUNTRY_NAME, REGION_ID) VALUES ('OR','OracleLand', 3);
    INSERT INTO COUNTRIES (COUNTRY_ID, COUNTRY_NAME, REGION_ID) VALUES ('JA','Javatopia', 4);


  6. Featureダイアログ

  7. 次のステップでは、データベースへの接続を確立するクラスを追加します。カスタム・データをどこで取得するかは、クラスを作成するときにメソッドを参照して決定されます。

    ApplicationController」を右クリックし、コンテキスト・メニューから「New」→「From Gallery」を選択します。New Galleryで、新しいJavaクラスを作成します。ConnectionFactoryという名前を付け、パッケージをdatabaseに変更します。

    OK」をクリックします。

  8. Featureダイアログ

    Featureダイアログ
  9. クラスのコードをすべて、次のコードに置き換えます。

    このコードによって、データベースへの接続が確立されます。


    package database;

    import java.sql.Connection;
    import java.sql.SQLException;

    import oracle.adfmf.framework.api.AdfmfJavaUtilities;

    // データベースへの接続を確立する
    public class ConnectionFactory {
    public ConnectionFactory() {
    super();
    }

    protected static Connection conn = null;

    public static Connection getConnection() throws Exception {
    if (conn == null) {
    try {
    String Dir = AdfmfJavaUtilities.getDirectoryPathRoot(AdfmfJavaUtilities.ApplicationDirectory);
    String connStr = "jdbc:sqlite:"+ Dir + "/sm.db";
    conn = new SQLite.JDBCDataSource(connStr).getConnection();
    } catch (SQLException e) {
    System.err.println(e.getMessage());
    }
    }

    return conn;
    }

    public static void closeConnection() {
    try {
    if (conn != null) {
    conn.close();
    conn = null;
    }
    } catch (Exception ex) {
    throw new RuntimeException(ex);
    }
    }
    }



  10. Features表
  11. 完了すると、ApplicationControllerプロジェクトは次のイメージのようになり、更新されたLifecycleListener.javaと、新しいConnectionFactory.javaファイルおよびinitialized.sqlファイルが追加されます。

  12. Features表
ステップ3:データ・レコードを取得するクラスの追加

この項では、CountryBOとCountryDCの2つのクラスを作成します。一方のクラスはページで使用されるデータ構造の定義に使用され、もう一方のクラスはネットワーク・ステータスを判定してWebサービスまたはローカル・データベースからレコードを取得します。

  1. 最初のセクションでは、すべてのcountry属性に対するすべてのアクセッサを定義して提供するクラスを作成します。

    ページで使用されるデータ構造を定義するクラスを作成します。「ViewController」プロジェクトを選択してNew Galleryを開き、GeneralカテゴリからJavaクラスを選択します。次に「Java Class」項目を選択して「OK」をクリックします。

  2. アプリケーション・ナビゲータ
  3. クラスの名前としてCountryBOと入力し、Packageプロパティをmobileに設定します。

  4. Features表
  5. 次のコードをコピーしてクラスに追加します。作業内容を保存します。

    このクラスの内容はほぼすべてJDeveloperによって生成されます。属性が作成されると、それら(Generateアクセッサ)のGetterとSetterを生成するコンテキスト・メニュー・オプションが表示され、プロパティ変更サポートも実装されます。


    package mobile;

    import oracle.adfmf.java.beans.PropertyChangeListener;
    import oracle.adfmf.java.beans.PropertyChangeSupport;

    // Defines data structure for the return of the data from the local db and web service
    // Supports updating records when their value changes with propertyChangeSupport (during Generate Accessors)

    public class CountryBO implements Comparable{

    private String id;
    private String country;
    private Integer regionId;
    private transient PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

    public CountryBO() {
    super();
    }

    public boolean equals(Object object) {
    if (this == object) {
    return true;
    }
    if (!(object instanceof CountryBO)) {
    return false;
    }
    final CountryBO other = (CountryBO)object;
    if (!(id == null ? other.id == null : id.equals(other.id))) {
    return false;
    }
    return true;
    }

    public int hashCode() {
    final int PRIME = 37;
    int result = 1;
    result = PRIME * result + ((id == null) ? 0 : id.hashCode());
    return result;
    }

    public int compareTo(Object o) {
    if (this.equals(o)){
    return 0;
    }
    else if (o instanceof CountryBO){
    return this.country.compareTo(((CountryBO)o).getCountry());
    }
    else{
    throw new ClassCastException("CountryBO expected.");
    }
    }

    public void setId(String countryId) {
    String oldCountryId = this.id;
    this.id = countryId;
    propertyChangeSupport.firePropertyChange("countryId", oldCountryId, countryId);
    }

    public void addPropertyChangeListener(PropertyChangeListener l) {
    propertyChangeSupport.addPropertyChangeListener(l);
    }

    public void removePropertyChangeListener(PropertyChangeListener l) {
    propertyChangeSupport.removePropertyChangeListener(l);
    }

    public String getId() {
    return id;
    }

    public void setCountry(String countryName) {
    String oldCountryName = this.country;
    this.country = countryName;
    propertyChangeSupport.firePropertyChange("countryName", oldCountryName, countryName);
    }

    public String getCountry() {
    return country;
    }

    public void setRegionId(Integer regionId) {
    Integer oldRegionId = this.regionId;
    this.regionId = regionId;
    propertyChangeSupport.firePropertyChange("regionId", oldRegionId, regionId);
    }

    public Integer getRegionId() {
    return regionId;
    }
    }


     

  6. 機能の追加
  7. 次の手順では、デバイスのネットワーク・ステータスを確認し、ネットワークが使用可能かどうかによってレコードをWebサービスまたはローカル・データベースから取得するクラスを作成します。コードを追加するとき、提示されたimport文をすべて追加してください。

    ViewControllerで「mobile」パッケージを選択してNew Galleryを開き、もう1つのクラスを作成します。CountryDCという名前を付け、そのパッケージ名がmobileになっていることを確認します。


    タスク・フローの作成

  8. コピーし、CountryDC.javaファイルを以下のコードに置換します。

    指摘するコードでいくつかのことがおきます。
    - 追加すべきimport文を受け入れるのに時間がかかることを確認してください。
    1: deviceScope.hardware.networkStatusプロパティを確認してネットワークが使用可能かどうかを判定するコード
    2: deviceScopeの値がNot_REACHABLEかどうかを確認します。次に、webサービスまたはローカル・データベースからレコードを取得するメソッドをコールします。
    3: ローカル・データベースからレコードを取得するコード
    4: 最後に、webサービスを使用してレコードを取得するコード


    package mobile;

    import java.sql.Connection;

    import java.util.ArrayList;
    import java.util.List;

    import oracle.adfmf.framework.api.AdfmfJavaUtilities;
    import mobile.CountryBO;
    import database.ConnectionFactory;

    import java.sql.ResultSet;
    import java.sql.Statement;

    import java.util.Arrays;
    import java.util.Collections;

    import oracle.adfmf.framework.api.AdfmfContainerUtilities;
    import oracle.adfmf.framework.api.GenericTypeBeanSerializationHelper;
    import oracle.adfmf.framework.exception.AdfInvocationException;
    import oracle.adfmf.util.GenericType;
    import oracle.adfmf.util.Utility;

    public class CountryDC {

    private static final String NOT_REACHABLE = "NotReachable"; // Indiates no network connectivity

    public CountryDC() {
    super();
    }

    // 1: deviceScope.hardware.networkStatusプロパティを確認してネットワークが使用可能かどうかを判定
    public CountryBO[] getCountries() {
    CountryBO[] countries = null;

    String networkStatus =
    (String)AdfmfJavaUtilities.evaluateELExpression("#{deviceScope.hardware.networkStatus}");

    // 2: deviceScopeの値がNOT_REACHABLEの場合はgetCountriesFromDBをコール、そうでなければgetCountiresFromWSをコール
    if (networkStatus.equals(NOT_REACHABLE)) {
    countries = getCountriesFromDB();
    } else {
    countries = getCountriesFromWS();
    }
    return countries;

    }

    // 3: ローカル・データベースからレコードを取得するためJDBCを使用
    private CountryBO[] getCountriesFromDB() {
    Connection conn = null;
    List returnValue = new ArrayList();

    try {
    conn = ConnectionFactory.getConnection();

    Statement stmt = conn.createStatement();
    ResultSet result = stmt.executeQuery("SELECT COUNTRY_ID, COUNTRY_NAME, REGION_ID FROM COUNTRIES;");
    while (result.next()) {
    CountryBO country = new CountryBO();
    Utility.ApplicationLogger.severe("Country: " + result.getString("COUNTRY_ID"));
    country.setId(result.getString("COUNTRY_ID"));
    country.setCountry(result.getString("COUNTRY_NAME"));
    country.setRegionId(new Integer(result.getInt("REGION_ID")));
    returnValue.add(country);
    }

    } catch (Exception ex) {
    Utility.ApplicationLogger.severe(ex.getMessage());
    ex.printStackTrace();
    throw new RuntimeException(ex);
    }
    Collections.sort(returnValue);
    return (CountryBO[])returnValue.toArray(new CountryBO[returnValue.size()]);
    }

    // 4: webサービスからレコード取得
    private CountryBO[] getCountriesFromWS() {
    try {
    GenericType genericReturnValue =
    (GenericType)AdfmfJavaUtilities.invokeDataControlMethod("SM_WS", null, "findCountry", new ArrayList(),
    new ArrayList(), new ArrayList());
    CountryBO[] returnValue =
    (CountryBO[])GenericTypeBeanSerializationHelper.fromGenericType(CountryBO[].class, genericReturnValue, "result");

    Arrays.sort(returnValue);
    return returnValue;

    } catch (AdfInvocationException aie) {
    if (AdfInvocationException.CATEGORY_WEBSERVICE.compareTo(aie.getErrorCategory()) == 0) {
    throw new RuntimeException("Error with the server. Please try later", aie);
    } else {
    throw new RuntimeException(aie);

    }
    }
    }
    }





  9. すべての作業内容を保存します。

    完成したクラスは、次のイメージのようになります。databaseConnectionFactoryというimport文はclassが見つからないため、その下に赤い波線が付いています。必要なクラスは、ApplicationControllerプロジェクトで作成されました。

    タスク・フロー

  10. この問題を解決するには、「ViewController」プロジェクトをダブルクリックしてそのプロパティを開きます。「Dependencies」ノードを選択し、Dependencies Projects and Archivesラベルの隣にある緑のプラス記号をクリックします。

    ApplicationController.jpr」を開き、「Build Output」チェック・ボックスを選択します。

    OK」をクリックして作業内容を保存します。

  11. タスク・フロー

    タスク・フロー
  12. CountryDC.java classに戻ると、ConnectionFactoryエラーが解決されています。

  13. プロパティ・インスペクタ

     

ブックマーク 印刷 すべて表示 | すべて非表示

トップに戻る
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.