Room.kt

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * 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.
 */
package androidx.room

import android.content.Context
import androidx.annotation.RestrictTo

/**
 * Utility functions for Room.
 */
// TODO (b/225972678) remove class and make top-level functions in Room 3.0.
open class Room {
    /** This type should not be instantiated as it contains only static methods. */
    @Deprecated("This type should not be instantiated as it contains only static methods. ")
    @SuppressWarnings("PrivateConstructorForUtilityClass")
    constructor()

    companion object {
        internal const val LOG_TAG = "ROOM"

        /**
         * The master table where room keeps its metadata information.
         */
        const val MASTER_TABLE_NAME = RoomMasterTable.TABLE_NAME
        private const val CURSOR_CONV_SUFFIX = "_CursorConverter"

        @Suppress("UNCHECKED_CAST")
        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
        @JvmStatic
        fun <T, C> getGeneratedImplementation(
            klass: Class<C>,
            suffix: String
        ): T {
            val fullPackage = klass.getPackage()!!.name
            val name: String = klass.canonicalName!!
            val postPackageName =
                if (fullPackage.isEmpty()) name else name.substring(fullPackage.length + 1)
            val implName = postPackageName.replace('.', '_') + suffix
            return try {
                val fullClassName = if (fullPackage.isEmpty()) {
                    implName
                } else {
                    "$fullPackage.$implName"
                }
                val aClass = Class.forName(
                    fullClassName, true, klass.classLoader
                ) as Class<T>
                aClass.newInstance()
            } catch (e: ClassNotFoundException) {
                throw RuntimeException(
                    "Cannot find implementation for ${klass.canonicalName}. $implName does not " +
                        "exist"
                )
            } catch (e: IllegalAccessException) {
                throw RuntimeException(
                    "Cannot access the constructor $klass.canonicalName"
                )
            } catch (e: InstantiationException) {
                throw RuntimeException(
                    "Failed to create an instance of $klass.canonicalName"
                )
            }
        }

        /**
         * Creates a RoomDatabase.Builder for an in memory database. Information stored in an in memory
         * database disappears when the process is killed.
         * Once a database is built, you should keep a reference to it and re-use it.
         *
         * @param context The context for the database. This is usually the Application context.
         * @param klass   The abstract class which is annotated with [Database] and extends
         * [RoomDatabase].
         * @param T     The type of the database class.
         * @return A `RoomDatabaseBuilder<T>` which you can use to create the database.
         */
        @JvmStatic
        fun <T : RoomDatabase> inMemoryDatabaseBuilder(
            context: Context,
            klass: Class<T>
        ): RoomDatabase.Builder<T> {
            return RoomDatabase.Builder(context, klass, null)
        }

        /**
         * Creates a RoomDatabase.Builder for a persistent database. Once a database is built, you
         * should keep a reference to it and re-use it.
         *
         * @param context The context for the database. This is usually the Application context.
         * @param klass   The abstract class which is annotated with [Database] and extends
         * [RoomDatabase].
         * @param name    The name of the database file.
         * @param T     The type of the database class.
         * @return A `RoomDatabaseBuilder<T>` which you can use to create the database.
         */
        @JvmStatic
        fun <T : RoomDatabase> databaseBuilder(
            context: Context,
            klass: Class<T>,
            name: String?
        ): RoomDatabase.Builder<T> {
            require(!name.isNullOrBlank()) {
                "Cannot build a database with null or empty name." +
                    " If you are trying to create an in memory database, use Room" +
                    ".inMemoryDatabaseBuilder"
            }
            return RoomDatabase.Builder(context, klass, name)
        }
    }
}