/* * SQLiteDemo.java * * Copyright � 1998-2011 Research In Motion Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Note: For the sake of simplicity, this sample application may not leverage * resource bundles and resource strings. However, it is STRONGLY recommended * that application developers make use of the localization features available * within the BlackBerry development platform to ensure a seamless application * experience across a variety of languages and geographies. For more information * on localizing your application, please refer to the BlackBerry Java Development * Environment Development Guide associated with this release. */ package com.rim.samples.device.sqlitedemo; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Enumeration; import javax.microedition.io.Connector; import javax.microedition.io.file.FileConnection; import javax.microedition.io.file.FileSystemRegistry; import net.rim.device.api.database.Database; import net.rim.device.api.database.DatabaseException; import net.rim.device.api.database.DatabaseFactory; import net.rim.device.api.database.DatabaseOptions; import net.rim.device.api.database.DatabaseSecurityOptions; import net.rim.device.api.io.IOUtilities; import net.rim.device.api.io.URI; import net.rim.device.api.system.CodeModuleManager; import net.rim.device.api.system.CodeSigningKey; import net.rim.device.api.ui.UiApplication; import net.rim.device.api.ui.component.Dialog; /** * This sample application demonstrates the use of a SQLite database and the * 'net.rim.device.api.database package'. A pre-configured database is included * with the project and will be copied to the default root location (provided an * SDCard is available) if a database does not already exist at that location. * The default root for SQLite databases is * 'file:///SDCard/databases/*project-name*'. Certain BlackBerry Smartphone * devices are capable of creating databases in eMMC memory which is of a fixed * capacity. Storage location for SQLite databases should be based on the * availability of eMMC memory, potential size of the database, and whether a * portable solution is required for a given application. * * This sample is a business directory application which uses the SQLite back * end database for persistent storage of its data. The database contains a * DirectoryItems table and an associated table, Category. The DirectoryItems * table contains a foreign key constraint on its category_id field which * references the corresponding field in the Category table. The applications's * user interface consists of a tree field which displays categories as nodes * and directory items as child nodes. The application allows for the * displaying, editing, adding, saving and deleting of items. Categories can * also be added or deleted. Deleting a category will result in all directory * items belonging to the category being deleted as well. * * The database created by this application is encrypted and access is * controlled by a code signing key. You will need to use the BlackBerry Signing * Authority Admin Tool to create a public/private key pair with the name "XYZ" * (See the BlackBerry Signing Authority Tool Administrator Guide for more * information). Replace the XYZ public key contained in this project with the * XYZ public key created with the BlackBerry Signing Authority Admin Tool. * Build the project and then use the BlackBerry Signing Authority Tool to sign * the resulting cod file with the XYZ private key. */ public final class SQLiteDemo extends UiApplication { private static final String DB_NAME = "SQLiteDemoDirectory"; /** * Entry point for this application * * @param args * Command line arguments (not used) * @throws Exception */ public static void main(final String[] args) throws Exception { // Create a new instance of the application and make the currently // running thread the application's event dispatch thread. final SQLiteDemo app = new SQLiteDemo(); app.enterEventDispatcher(); } /** * Creates a new SQLiteDemo object * * @throws Exception */ public SQLiteDemo() throws Exception { // Determine if an SDCard is present boolean sdCardPresent = false; String root = null; final Enumeration e = FileSystemRegistry.listRoots(); while (e.hasMoreElements()) { root = (String) e.nextElement(); if (root.equalsIgnoreCase("sdcard/")) { sdCardPresent = true; } } if (!sdCardPresent) { UiApplication.getUiApplication().invokeLater(new Runnable() { public void run() { Dialog.alert("This application requires an SD card to be present. Exiting application..."); System.exit(0); } }); } else { final String dbLocation = "/SDCard/databases/SQLite Demo/"; // Create URI final URI uri = URI.create(dbLocation + DB_NAME); // Open or create a plain text database. This will create the // directory and file defined by the URI (if they do not already // exist). Database db = DatabaseFactory.openOrCreate(uri); // Close the database in case it is blank and we need to write to // the file db.close(); // Open a connection to the database file final FileConnection fileConnection = (FileConnection) Connector.open("file://" + dbLocation + DB_NAME); // If the file is blank, copy the pre-defined database from this // module to the SDCard. if (fileConnection.exists() && fileConnection.fileSize() == 0) { readAndWriteDatabaseFile(fileConnection); } // Retrieve the code signing key for the XYZ key file final CodeSigningKey codeSigningKey = CodeSigningKey.get(CodeModuleManager .getModuleHandle("SQLiteDemo"), "XYZ"); try { // Encrypt and protect the database. If the database is already // encrypted, the method will exit gracefully. DatabaseFactory.encrypt(uri, new DatabaseSecurityOptions( codeSigningKey)); } catch (final DatabaseException dbe) { errorDialog("Encryption failed - " + dbe.toString()); } // Create a new DatabaseOptions object forcing foreign key // constraints final DatabaseOptions databaseOptions = new DatabaseOptions(); databaseOptions.set("foreign_key_constraints", "on"); // Open the database db = DatabaseFactory.open(uri, databaseOptions); // Create a new main screen and push it onto the display stack final SQLiteDemoScreen screen = new SQLiteDemoScreen(new SQLManager(db)); pushScreen(screen); } } /** * Copies the pre-defined database from this module to the location * specified by the fileConnection argument. * * @param fileConnection * File connection to the database location */ public void readAndWriteDatabaseFile(final FileConnection fileConnection) throws IOException { OutputStream outputStream = null; InputStream inputStream = null; // Open an input stream to the pre-defined encrypted database bundled // within this module. inputStream = getClass().getResourceAsStream("/" + DB_NAME); // Open an output stream to the newly created file outputStream = fileConnection.openOutputStream(); // Read data from the input stream and write the data to the // output stream. final byte[] bytes = IOUtilities.streamToBytes(inputStream); outputStream.write(bytes); // Close the connections if (fileConnection != null) { fileConnection.close(); } if (outputStream != null) { outputStream.close(); } if (inputStream != null) { inputStream.close(); } } /** * Presents a dialog to the user with a given message * * @param message * The text to display */ public static void errorDialog(final String message) { UiApplication.getUiApplication().invokeLater(new Runnable() { public void run() { Dialog.alert(message); } }); } }