15ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar/* 25ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * Copyright (C) 2016 The Android Open Source Project 35ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * 45ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 55ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * you may not use this file except in compliance with the License. 65ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * You may obtain a copy of the License at 75ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * 85ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 95ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * 105ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * Unless required by applicable law or agreed to in writing, software 115ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 125ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * See the License for the specific language governing permissions and 145ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * limitations under the License. 155ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar */ 165ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar 1764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarpackage android.arch.persistence.room 185ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar 1964db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.Context 2064db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.DatabaseProcessor 2164db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.ProcessorErrors 2264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.DaoMethod 2364db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Warning 2464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.writer.DaoWriter 2564db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.writer.DatabaseWriter 265ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyarimport com.google.auto.common.BasicAnnotationProcessor 275ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyarimport com.google.auto.common.MoreElements 285ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyarimport com.google.common.collect.SetMultimap 29a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyarimport java.io.File 305ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyarimport javax.annotation.processing.SupportedSourceVersion 315ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyarimport javax.lang.model.SourceVersion 325ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyarimport javax.lang.model.element.Element 335ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar 345ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar/** 355ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar * The annotation processor for Room. 365ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar */ 375ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar@SupportedSourceVersion(SourceVersion.RELEASE_7) 385ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyarclass RoomProcessor : BasicAnnotationProcessor() { 395ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar override fun initSteps(): MutableIterable<ProcessingStep>? { 405ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar val context = Context(processingEnv) 41275e7088223c097c1a2df718455bede42bc9efedYigit Boyar return arrayListOf(DatabaseProcessingStep(context)) 425ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar } 435ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar 44a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar override fun getSupportedOptions(): MutableSet<String> { 45a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar return Context.ARG_OPTIONS.toMutableSet() 46a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 47a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar 4888865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar class DatabaseProcessingStep(context: Context) : ContextBoundProcessingStep(context) { 495ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar override fun process(elementsByAnnotation: SetMultimap<Class<out Annotation>, Element>) 505ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar : MutableSet<Element> { 5188865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar // TODO multi step support 5288865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar val databases = elementsByAnnotation[Database::class.java] 535ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar ?.map { 54aa82fce1d73394bdc7f4c2510cf94a3572032b24Yigit Boyar DatabaseProcessor(context, MoreElements.asType(it)).process() 555ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar } 5688865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar val allDaoMethods = databases?.flatMap { it.daoMethods } 5788865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar allDaoMethods?.let { 58d2649c45a34db46fb03a24dcb2a443a92298b5adSergey Vasilinets prepareDaosForWriting(databases, it) 5988865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar it.forEach { 602236f645056249c7b7b7bd9cfb67d8e5256c446dYigit Boyar DaoWriter(it.dao, context.processingEnv).write(context.processingEnv) 6188865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 6288865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 6388865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar 64a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar databases?.forEach { db -> 65a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar DatabaseWriter(db).write(context.processingEnv) 66a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar if (db.exportSchema) { 67a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar val schemaOutFolder = context.schemaOutFolder 68a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar if (schemaOutFolder == null) { 69a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar context.logger.w(Warning.MISSING_SCHEMA_LOCATION, db.element, 70a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar ProcessorErrors.MISSING_SCHEMA_EXPORT_DIRECTORY) 71a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } else { 72a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar if (!schemaOutFolder.exists()) { 73a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar schemaOutFolder.mkdirs() 74a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 75a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar val qName = db.element.qualifiedName.toString() 76a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar val dbSchemaFolder = File(schemaOutFolder, qName) 77a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar if (!dbSchemaFolder.exists()) { 78a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar dbSchemaFolder.mkdirs() 79a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 80a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar db.exportSchema(File(dbSchemaFolder, "${db.version}.json")) 81a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 82a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 8388865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 84d2649c45a34db46fb03a24dcb2a443a92298b5adSergey Vasilinets context.databaseVerifier?.closeConnection() 855ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar return mutableSetOf() 865ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar } 875ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar override fun annotations(): MutableSet<out Class<out Annotation>> { 88275e7088223c097c1a2df718455bede42bc9efedYigit Boyar return mutableSetOf(Database::class.java, Dao::class.java, Entity::class.java) 895ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar } 905ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar 9188865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar /** 9288865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * Traverses all dao methods and assigns them suffix if they are used in multiple databases. 9388865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar */ 9464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar private fun prepareDaosForWriting( 9564db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar databases: List<android.arch.persistence.room.vo.Database>, 9664db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar daoMethods: List<DaoMethod>) { 9788865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar daoMethods.groupBy { it.dao.typeName } 9888865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar // if used only in 1 database, nothing to do. 9988865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar .filter { entry -> entry.value.size > 1 } 10088865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar .forEach { entry -> 10188865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar entry.value.groupBy { daoMethod -> 10288865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar // first suffix guess: Database's simple name 10388865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar val db = databases.first { db -> db.daoMethods.contains(daoMethod) } 10488865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar db.typeName.simpleName() 105d2649c45a34db46fb03a24dcb2a443a92298b5adSergey Vasilinets }.forEach { (dbName, methods) -> 10688865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar if (methods.size == 1) { 10788865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar //good, db names do not clash, use db name as suffix 10888865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar methods.first().dao.setSuffix(dbName) 10988865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } else { 11088865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar // ok looks like a dao is used in 2 different databases both of 11188865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar // which have the same name. enumerate. 11288865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar methods.forEachIndexed { index, method -> 11388865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar method.dao.setSuffix("${dbName}_$index") 11488865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 11588865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 11688865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 1175ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar } 1185ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar } 1195ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar } 1205ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar 1215ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar abstract class ContextBoundProcessingStep(val context: Context) : ProcessingStep 1225ce90e9725b8c9e8fdcef114694d6984a0ef3141Yigit Boyar} 123