├── .gitignore ├── Chapter01 ├── .gitignore ├── gradle.properties ├── settings.gradle.kts ├── src │ └── main │ │ └── kotlin │ │ ├── 1_Hello_Kotlin.kt │ │ ├── 3_Values.kt │ │ ├── 11_Interfaces.kt │ │ ├── 4_Comparison.kt │ │ ├── 13_Data_Classes.kt │ │ ├── 5_Declaring_Function.kt │ │ ├── 14_Extension_Functions.kt │ │ ├── 2_Type_Inference.kt │ │ ├── 6_Null_Safety.kt │ │ ├── 10_Classes.kt │ │ ├── 9_String_Interpolation.kt │ │ ├── 12_Abstract_Classes.kt │ │ ├── 8_Control_Flow.kt │ │ └── 7_Data_Structures.kt ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── build.gradle.kts ├── gradlew.bat └── gradlew ├── Chapter02 ├── .gitignore ├── gradle.properties ├── settings.gradle.kts ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── build.gradle.kts ├── src │ └── main │ │ └── kotlin │ │ ├── 6_StaticFactoryMethod.kt │ │ ├── 1_Singleton.kt │ │ ├── 2_FactoryMethod.kt │ │ ├── 5_Prototype.kt │ │ ├── 4_Builder.kt │ │ └── 3_AbstractFactory.kt ├── gradlew.bat └── gradlew ├── Chapter03 ├── .gitignore ├── gradle.properties ├── settings.gradle.kts ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── build.gradle.kts ├── src │ └── main │ │ └── kotlin │ │ ├── 7_Proxy.kt │ │ ├── 4_Composite.kt │ │ ├── 6_Flyweight.kt │ │ ├── 3_Bridge.kt │ │ ├── 5_Facade.kt │ │ ├── 1_Decorator.kt │ │ └── 2_Adapter.kt ├── gradlew.bat └── gradlew ├── Chapter04 ├── .gitignore ├── gradle.properties ├── settings.gradle ├── build.gradle.kts ├── src │ └── main │ │ └── kotlin │ │ ├── 4_Command.kt │ │ ├── 10_TemplateMethod.kt │ │ ├── 6_Interpreter.kt │ │ ├── 8_Memento.kt │ │ ├── 1_Strategy.kt │ │ ├── 3_State.kt │ │ ├── 11_Observable.kt │ │ ├── 2_Iterator.kt │ │ ├── 7_Mediator.kt │ │ ├── 5_ChainOfResponsibility.kt │ │ └── 9_Visitor.kt ├── gradlew.bat └── gradlew ├── Chapter05 ├── .gitignore ├── gradle.properties ├── settings.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── src │ └── main │ │ └── kotlin │ │ ├── 6_Closures.kt │ │ ├── 2_ImmutableIterator.kt │ │ ├── 1_MutableIterator.kt │ │ ├── 3_Race.kt │ │ ├── 4_FunctionsAsValues.kt │ │ ├── 5_HigherOrderFunctions.kt │ │ ├── 8_Memoisation.kt │ │ ├── 7_Currying.kt │ │ └── 9_Tail_Recursion.kt ├── build.gradle.kts ├── gradlew.bat └── gradlew ├── Chapter07 ├── .gitignore ├── gradle.properties ├── settings.gradle.kts ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── src │ └── main │ │ └── kotlin │ │ ├── 4_Reduce.kt │ │ ├── 1_Map.kt │ │ ├── 2_Filter.kt │ │ ├── 5_Flat.kt │ │ ├── 11_Actors.kt │ │ ├── 3_Find.kt │ │ ├── 9_Channels.kt │ │ ├── 10_Producers.kt │ │ ├── 6_Sequence.kt │ │ ├── 14_Conflate.kt │ │ ├── 7_Sequences_are_Lazy.kt │ │ ├── 13_Buffered_Flows.kt │ │ ├── 12_Buffered_Channels.kt │ │ └── 8_Flows.kt ├── build.gradle.kts ├── gradlew.bat └── gradlew ├── Chapter08 ├── .gitignore ├── gradle.properties ├── settings.gradle.kts ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── build.gradle.kts ├── src │ └── main │ │ └── kotlin │ │ ├── 9_Mutex.kt │ │ ├── 1_Deferred_value.kt │ │ ├── 5_Fan_Out.kt │ │ ├── 8_Unbiased_Select.kt │ │ ├── 6_Fan_In.kt │ │ ├── 7_Racing.kt │ │ ├── 3_Scheduler.kt │ │ ├── 10_Sidekick_Channel.kt │ │ ├── 4_Pipeline.kt │ │ └── 2_Barrier.kt ├── gradlew.bat └── gradlew ├── Chapter09 ├── .gitignore ├── gradle.properties ├── settings.gradle.kts ├── src │ └── main │ │ └── kotlin │ │ ├── 5_With.kt │ │ ├── 11_Constants.kt │ │ ├── 3_Also.kt │ │ ├── 8_Inline_Functions.kt │ │ ├── 4_Run.kt │ │ ├── 7_TryWithResource.kt │ │ ├── 2_Apply.kt │ │ ├── 12_Constructors.kt │ │ ├── 15_Validations.kt │ │ ├── 6_Instance_Checks.kt │ │ ├── 14_Explicit_Asynchronicity.kt │ │ ├── 9_ADT.kt │ │ ├── 1_Let.kt │ │ ├── 13_Dealing_with_Null.kt │ │ ├── 10_Reified_Generics.kt │ │ └── 16_Sealead_classes.kt ├── build.gradle.kts └── gradlew.bat ├── Chapter10 ├── .gitignore ├── gradle.properties ├── settings.gradle.kts ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── README.md ├── src │ ├── main │ │ └── kotlin │ │ │ ├── db.kt │ │ │ ├── server.kt │ │ │ ├── cats.kt │ │ │ └── cats │ │ │ └── CatService.kt │ └── test │ │ └── kotlin │ │ └── ServerTest.kt ├── build.gradle.kts └── gradlew.bat ├── Chapter11 ├── .gitignore ├── gradle.properties ├── settings.gradle.kts ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── README.md ├── src │ ├── main │ │ └── kotlin │ │ │ ├── db.kt │ │ │ ├── cats.kt │ │ │ └── server.kt │ └── test │ │ └── kotlin │ │ └── ServerTest.kt ├── build.gradle.kts └── gradlew.bat ├── Chapter06 ├── .gitignore ├── gradle.properties ├── settings.gradle.kts ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── build.gradle.kts ├── src │ └── main │ │ └── kotlin │ │ ├── 3_Async.kt │ │ ├── 7_Dispatchers.kt │ │ ├── 6_Timeouts.kt │ │ ├── 2_Launch.kt │ │ ├── 5_Cancelling_Coroutines.kt │ │ ├── 8_Structured_Concurrency.kt │ │ ├── 1_Threads.kt │ │ └── 4_Threads_vs_Coroutines.kt ├── gradlew.bat └── gradlew ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /Chapter01/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build 3 | .idea -------------------------------------------------------------------------------- /Chapter02/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .gradle 3 | .idea -------------------------------------------------------------------------------- /Chapter03/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build -------------------------------------------------------------------------------- /Chapter04/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build -------------------------------------------------------------------------------- /Chapter05/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build -------------------------------------------------------------------------------- /Chapter07/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build -------------------------------------------------------------------------------- /Chapter08/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build -------------------------------------------------------------------------------- /Chapter09/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build -------------------------------------------------------------------------------- /Chapter10/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build -------------------------------------------------------------------------------- /Chapter11/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build -------------------------------------------------------------------------------- /Chapter04/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official -------------------------------------------------------------------------------- /Chapter05/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official -------------------------------------------------------------------------------- /Chapter06/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build 4 | -------------------------------------------------------------------------------- /Chapter01/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /Chapter02/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /Chapter03/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /Chapter06/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /Chapter07/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /Chapter08/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /Chapter09/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /Chapter10/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /Chapter11/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /Chapter04/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'Chapter4' 2 | 3 | -------------------------------------------------------------------------------- /Chapter05/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'Chapter5' 2 | 3 | -------------------------------------------------------------------------------- /Chapter01/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | rootProject.name = "Chapter1" 3 | 4 | -------------------------------------------------------------------------------- /Chapter02/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | rootProject.name = "Chapter2" 3 | 4 | -------------------------------------------------------------------------------- /Chapter03/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | rootProject.name = "Chapter3" 3 | 4 | -------------------------------------------------------------------------------- /Chapter06/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | rootProject.name = "Chapter6" 3 | 4 | -------------------------------------------------------------------------------- /Chapter07/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | rootProject.name = "Chapter7" 3 | 4 | -------------------------------------------------------------------------------- /Chapter08/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | rootProject.name = "Chapter8" 3 | 4 | -------------------------------------------------------------------------------- /Chapter09/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | rootProject.name = "Chapter9" 3 | 4 | -------------------------------------------------------------------------------- /Chapter10/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | rootProject.name = "CatsHostel" 3 | 4 | -------------------------------------------------------------------------------- /Chapter11/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | rootProject.name = "CatsShelterVertx" 3 | 4 | -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/5_With.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | with(JamesBond()) { 3 | name = "Pierce Brosnan" 4 | 5 | println(this.name) 6 | } 7 | } -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/1_Hello_Kotlin.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * I'm a block comment 3 | */ 4 | fun main() { 5 | // I'm a regular comment 6 | println("Hello Kotlin") 7 | } -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/3_Values.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val greeting = "Hi" 3 | 4 | // Doesn't work 5 | // greeting = "Bye" // Val cannot be reassigned 6 | } -------------------------------------------------------------------------------- /Chapter01/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Kotlin-Design-Patterns-and-Best-Practices/HEAD/Chapter01/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Chapter02/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Kotlin-Design-Patterns-and-Best-Practices/HEAD/Chapter02/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Chapter03/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Kotlin-Design-Patterns-and-Best-Practices/HEAD/Chapter03/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Chapter05/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Kotlin-Design-Patterns-and-Best-Practices/HEAD/Chapter05/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Chapter06/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Kotlin-Design-Patterns-and-Best-Practices/HEAD/Chapter06/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Chapter07/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Kotlin-Design-Patterns-and-Best-Practices/HEAD/Chapter07/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Chapter08/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Kotlin-Design-Patterns-and-Best-Practices/HEAD/Chapter08/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Chapter10/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Kotlin-Design-Patterns-and-Best-Practices/HEAD/Chapter10/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Chapter11/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Kotlin-Design-Patterns-and-Best-Practices/HEAD/Chapter11/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/11_Interfaces.kt: -------------------------------------------------------------------------------- 1 | import kotlin.random.* 2 | 3 | fun main() { 4 | 5 | } 6 | 7 | interface DiceRoller { 8 | fun rollDice(): Int = Random.nextInt(0, 6) 9 | } -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/4_Comparison.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val a = 1000 3 | val b = 1000 4 | println(a == b) // true 5 | println(a.equals(b)) // true 6 | println(a === b) // Still true 7 | } -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/11_Constants.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | println(Spock.SENSE_OF_HUMOR) 3 | } 4 | 5 | class Spock { 6 | companion object { 7 | val SENSE_OF_HUMOR = "None" 8 | } 9 | } 10 | 11 | -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/3_Also.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val l = (1..100).toList() 3 | 4 | l.filter { it % 2 == 0 } 5 | // Prints, but doesn't mutate the collection 6 | .also { println(it) } 7 | .map { it * it } 8 | } -------------------------------------------------------------------------------- /Chapter05/src/main/kotlin/6_Closures.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | 3 | val next = counter() 4 | println(next()) 5 | println(next()) 6 | println(next()) 7 | } 8 | 9 | fun counter(): () -> Int { 10 | var i = 0 11 | return { i++ } 12 | } -------------------------------------------------------------------------------- /Chapter01/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /Chapter02/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /Chapter03/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /Chapter05/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /Chapter06/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /Chapter07/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /Chapter08/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /Chapter10/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /Chapter11/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/8_Inline_Functions.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | logBeforeAfter { 3 | "Inlining" 4 | } 5 | } 6 | 7 | inline fun logBeforeAfter(block: () -> String) { 8 | println("Before") 9 | println(block()) 10 | println("After") 11 | } -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/4_Run.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val lowerCaseName = JamesBond().run { 3 | name = "ROGER MOORE" 4 | movie = "THE MAN WITH THE GOLDEN GUN" 5 | name.toLowerCase() // <= Not JamesBond type 6 | } 7 | 8 | println(lowerCaseName) 9 | } -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/13_Data_Classes.kt: -------------------------------------------------------------------------------- 1 | data class User(val username: String, private val password: String) { 2 | fun hidePassword() = "*".repeat(password.length) 3 | } 4 | 5 | fun main() { 6 | val user = User("Alexey", "abcd1234") 7 | println(user.hidePassword()) 8 | } -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/4_Reduce.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val numbers = 1..100 3 | 4 | var sum = 0 5 | for (n in numbers) { 6 | sum += n 7 | } 8 | println(sum) 9 | 10 | val reduced: Int = (1..100).reduce { sum, n -> sum + n } 11 | println(reduced) 12 | } -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/7_TryWithResource.kt: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader 2 | import java.io.FileReader 3 | 4 | fun main() { 5 | val br = BufferedReader(FileReader("./src/main/kotlin/7_TryWithResource.kt")) 6 | 7 | br.use { 8 | println(it.readLines()) 9 | } 10 | } -------------------------------------------------------------------------------- /Chapter05/src/main/kotlin/2_ImmutableIterator.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val emptyList = printAndClear(mutableListOf("a", "b", "c")) 3 | } 4 | private fun printAndClear(list: MutableList): MutableList { 5 | for (e in list) { 6 | println(e) 7 | } 8 | return mutableListOf() 9 | } -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/5_Declaring_Function.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | greet(getGreeting()) 3 | } 4 | 5 | fun greet(greeting: String) { 6 | println(greeting) 7 | } 8 | 9 | // Short form 10 | // fun greet(greeting: String) = println(greeting) 11 | 12 | fun getGreeting(): String { 13 | return "Hello, Kotlin!" 14 | } -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/1_Map.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | 3 | val letters = 'a'..'z' 4 | val ascii = mutableListOf() 5 | 6 | for (l in letters) { 7 | ascii.add(l.toInt()) 8 | } 9 | 10 | println(ascii) 11 | val result: List = ('a'..'z').map { it.toInt() } 12 | println(result) 13 | } 14 | -------------------------------------------------------------------------------- /Chapter01/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") version "1.6.0" 5 | application 6 | } 7 | 8 | group = "me.soshin" 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | tasks.withType() { 15 | kotlinOptions.jvmTarget = "1.8" 16 | } 17 | -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/2_Apply.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val `007` = JamesBond().apply { 3 | name = "Sean Connery" 4 | movie = "Dr. No" 5 | } 6 | 7 | println(`007`.name) 8 | } 9 | 10 | class JamesBond { 11 | lateinit var name: String 12 | lateinit var movie: String 13 | lateinit var alsoStarring: String 14 | } -------------------------------------------------------------------------------- /Chapter02/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") version "1.6.0" 5 | } 6 | 7 | group = "me.soshin" 8 | version = "1.0-SNAPSHOT" 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | tasks.withType() { 15 | kotlinOptions.jvmTarget = "1.8" 16 | } -------------------------------------------------------------------------------- /Chapter03/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") version "1.6.0" 5 | } 6 | 7 | group = "me.soshin" 8 | version = "1.0-SNAPSHOT" 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | tasks.withType() { 15 | kotlinOptions.jvmTarget = "1.8" 16 | } -------------------------------------------------------------------------------- /Chapter04/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") version "1.6.0" 5 | } 6 | 7 | group = "me.soshin" 8 | version = "1.0-SNAPSHOT" 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | tasks.withType() { 15 | kotlinOptions.jvmTarget = "1.8" 16 | } -------------------------------------------------------------------------------- /Chapter05/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") version "1.6.0" 5 | } 6 | 7 | group = "me.soshin" 8 | version = "1.0-SNAPSHOT" 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | tasks.withType < KotlinCompile > () { 15 | kotlinOptions.jvmTarget = "1.8" 16 | } -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/14_Extension_Functions.kt: -------------------------------------------------------------------------------- 1 | data class Password(val password: String) { 2 | fun hidePassword() = "*".repeat(password.length) 3 | } 4 | 5 | fun String.hidePassword() = "*".repeat(this.length) 6 | 7 | fun main() { 8 | val password: String = "secretpassword" 9 | 10 | println("Password: ${password.hidePassword()}") 11 | } -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/2_Type_Inference.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | var greeting = "Hello Kotlin" 3 | 4 | // Explicit type: 5 | // var greeting: String = "Hello Kotlin" 6 | println(greeting) 7 | 8 | // That won't work, Kotlin is a typed language 9 | //greeting = 1 // The integer literal does not conform to the expected type String 10 | } -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/12_Constructors.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val c = User("Alexey") 3 | 4 | println(c.resetPassword) 5 | } 6 | 7 | // Don't do this 8 | /* 9 | class User(val name: String, val resetPassword: Boolean) { 10 | constructor(name: String) : this(name, true) 11 | } */ 12 | 13 | class User(val name: String, val resetPassword: Boolean = true) -------------------------------------------------------------------------------- /Chapter02/src/main/kotlin/6_StaticFactoryMethod.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | Server.withPort(8080) 3 | } 4 | 5 | class Server private constructor(port: Long) { 6 | 7 | init { 8 | println("Server started on port $port") 9 | } 10 | 11 | companion object { 12 | fun withPort(port: Long): Server { 13 | return Server(port) 14 | } 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/6_Null_Safety.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | // Won't compile 3 | // val s: String = null // Null can not be a value of a non-null type String 4 | 5 | // Won't compile 6 | // printLength(null) // Null can not be a value of a non-null type String 7 | 8 | var willInitializeLater: String? = null 9 | } 10 | 11 | fun printLength(s: String) { 12 | println(s.length) 13 | } -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/2_Filter.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | 3 | val numbers = 1..100 4 | 5 | val notFizzbuzz = mutableListOf() 6 | 7 | for (n in numbers) { 8 | if (n % 3 == 0 || n % 5 == 0) { 9 | notFizzbuzz.add(n) 10 | } 11 | } 12 | 13 | println(notFizzbuzz) 14 | val filtered: List = (1..100).filter { it % 3 == 0 || it % 5 == 0 } 15 | println(filtered) 16 | } -------------------------------------------------------------------------------- /Chapter05/src/main/kotlin/1_MutableIterator.kt: -------------------------------------------------------------------------------- 1 | import java.util.* 2 | 3 | fun main() { 4 | // Will cause ConcurrentModificationException 5 | printAndClear(mutableListOf("a", "b", "c")) 6 | 7 | val firstEdition = Triple("Design Patterns with Kotlin", 310, 2018) 8 | } 9 | 10 | private fun printAndClear(list: MutableList) { 11 | for (e in list) { 12 | println(e) 13 | list.remove(e) 14 | } 15 | } -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/5_Flat.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val listOfLists: List> = listOf(listOf(1, 2), listOf(3, 4, 5), listOf(6, 7, 8)) 3 | 4 | val flattened = mutableListOf() 5 | 6 | for (list in listOfLists) { 7 | flattened.addAll(list) 8 | } 9 | 10 | println(flattened) 11 | 12 | val flat: List = listOfLists.flatten() 13 | println(flat) 14 | println(listOfLists.flatMap { it }) 15 | } -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/11_Actors.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.channels.actor 2 | import kotlinx.coroutines.channels.consumeEach 3 | import kotlinx.coroutines.runBlocking 4 | 5 | fun main() { 6 | runBlocking { 7 | val actor = actor { 8 | channel.consumeEach { 9 | println(it) 10 | } 11 | } 12 | 13 | (1..10).forEach { 14 | actor.send(it) 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/3_Find.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | 3 | val numbers = (1..100).reversed() 4 | 5 | println(findFizzbuzz(numbers.toList())) 6 | val found: Int? = (1..100).find { it % 3 == 0 && it % 5 == 0 } 7 | println(found) 8 | } 9 | 10 | fun findFizzbuzz(numbers: List): Int? { 11 | for (n in numbers) { 12 | if (n % 3 == 0 && n % 5 == 0) { 13 | return n 14 | } 15 | } 16 | return null 17 | } -------------------------------------------------------------------------------- /Chapter02/src/main/kotlin/1_Singleton.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | Logger.log("Hello World") 3 | } 4 | 5 | /** 6 | * Object keyword will create a Singleton 7 | */ 8 | object Logger { 9 | init { 10 | println("I was accessed for the first time") 11 | 12 | // Initialization logic goes here 13 | } 14 | 15 | fun log(message: String) { 16 | println("Logging $message") 17 | } 18 | // More code goes here 19 | } 20 | 21 | -------------------------------------------------------------------------------- /Chapter08/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") version "1.6.0" 5 | } 6 | 7 | group = "me.soshin" 8 | version = "1.0-SNAPSHOT" 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | dependencies { 15 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1") 16 | } 17 | 18 | tasks.withType() { 19 | kotlinOptions.jvmTarget = "1.8" 20 | } -------------------------------------------------------------------------------- /Chapter06/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") version "1.6.0" 5 | } 6 | 7 | group = "com.depop" 8 | version = "1.0-SNAPSHOT" 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | dependencies { 15 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1") 16 | } 17 | 18 | 19 | tasks.withType() { 20 | kotlinOptions.jvmTarget = "1.8" 21 | } -------------------------------------------------------------------------------- /Chapter07/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") version "1.6.0" 5 | } 6 | 7 | group = "me.soshin" 8 | version = "1.0-SNAPSHOT" 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | dependencies { 15 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1") 16 | 17 | } 18 | 19 | tasks.withType() { 20 | kotlinOptions.jvmTarget = "1.8" 21 | } -------------------------------------------------------------------------------- /Chapter06/src/main/kotlin/3_Async.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | import java.util.* 3 | 4 | fun main() { 5 | 6 | runBlocking { 7 | val job: Deferred = fastUuidAsync() 8 | println(job.await()) 9 | } 10 | } 11 | 12 | fun fastUuidAsync() = GlobalScope.async { 13 | UUID.randomUUID() 14 | } 15 | 16 | fun slowUuidAsync() = GlobalScope.async { 17 | repeat(10_000_000) { 18 | UUID.randomUUID() 19 | } 20 | UUID.randomUUID() 21 | } -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/15_Validations.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | printNameLength(Profile(null)) 3 | } 4 | 5 | fun printNameLength(p: Profile) { 6 | requireNotNull(p.firstName) 7 | } 8 | 9 | data class Profile(val firstName: String?) 10 | 11 | class HttpClient { 12 | var body: String? = null 13 | var url: String = "" 14 | 15 | fun postRequest() { 16 | check(body != null) { 17 | "Body must be set in POST requests" 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Chapter10/README.md: -------------------------------------------------------------------------------- 1 | # Cats Hostel - Ktor 2 | 3 | This is an example application for managing cats written in Ktor framework 4 | 5 | ## Setup 6 | You need PostgreSQL installed. 7 | 8 | After you have PostgreSQL, run the following commands to set up your database: 9 | ``` 10 | createuser cats_admin -W -d 11 | createdb cats_db -U cats_admin 12 | psql -U cats_admin -c "create table if not exists cats(id bigserial primary key, name varchar(20) not null unique, age integer)" cats_db 13 | ``` -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/9_Channels.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.channels.Channel 2 | import kotlinx.coroutines.launch 3 | import kotlinx.coroutines.runBlocking 4 | 5 | fun main() { 6 | runBlocking { 7 | val chan = Channel() 8 | 9 | launch { 10 | for (c in chan) { 11 | println(c) 12 | } 13 | } 14 | 15 | (1..10).forEach { 16 | chan.send(it) 17 | } 18 | chan.close() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Chapter11/README.md: -------------------------------------------------------------------------------- 1 | # Cats Hostel - Vert.x 2 | This is an example application for managing cats written in Vert.x framework 3 | 4 | 5 | ## Setup 6 | You need PostgreSQL installed. 7 | 8 | After you have PostgreSQL, run the following commands to set up your database: 9 | ``` 10 | createuser cats_admin -W -d && 11 | createdb cats_db -U cats_admin && 12 | psql -U cats_admin -c "create table if not exists cats(id bigserial primary key, name varchar(20) not null unique, age integer)" cats_db 13 | ``` -------------------------------------------------------------------------------- /Chapter05/src/main/kotlin/3_Race.kt: -------------------------------------------------------------------------------- 1 | import kotlin.concurrent.thread 2 | 3 | fun main() { 4 | 5 | val scores = listOf(Player(0)) 6 | 7 | val threads = List(2) { 8 | thread { 9 | for (i in 1..1000) { 10 | scores[0].score = scores[0].score + 1 11 | } 12 | println("Done") 13 | } 14 | } 15 | 16 | for (t in threads) { 17 | t.join() 18 | } 19 | 20 | println(scores[0].score) 21 | } 22 | 23 | private data class Player(var score: Int) 24 | -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/10_Producers.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.channels.consumeEach 2 | import kotlinx.coroutines.channels.produce 3 | import kotlinx.coroutines.launch 4 | import kotlinx.coroutines.runBlocking 5 | 6 | fun main() { 7 | runBlocking { 8 | val chan = produce { 9 | (1..10).forEach { 10 | send(it) 11 | } 12 | } 13 | 14 | launch { 15 | chan.consumeEach { 16 | println(it) 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/6_Sequence.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val seq: Sequence = generateSequence(1L) { it + 1 } 3 | 4 | //seq.forEach { println(it) } 5 | 6 | (1..100).asSequence() 7 | 8 | val fibSeq = sequence { 9 | var a = 0 10 | var b = 1 11 | yield(a) 12 | yield(b) 13 | while (true) { 14 | yield(a + b) 15 | val t = a 16 | a = b 17 | b += t 18 | } 19 | } 20 | 21 | fibSeq.take(10).forEach { 22 | println(it) 23 | } 24 | } -------------------------------------------------------------------------------- /Chapter09/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") version "1.6.0" 5 | } 6 | 7 | group = "me.soshin" 8 | version = "1.0-SNAPSHOT" 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | dependencies { 15 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2") 16 | 17 | testImplementation(kotlin("test-junit")) 18 | } 19 | 20 | tasks.test { 21 | useJUnit() 22 | } 23 | 24 | tasks.withType() { 25 | kotlinOptions.jvmTarget = "1.8" 26 | } -------------------------------------------------------------------------------- /Chapter06/src/main/kotlin/7_Dispatchers.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.Dispatchers 2 | import kotlinx.coroutines.GlobalScope 3 | import kotlinx.coroutines.launch 4 | import kotlinx.coroutines.runBlocking 5 | 6 | fun main() { 7 | runBlocking { 8 | launch { 9 | println(Thread.currentThread().name) 10 | } 11 | GlobalScope.launch { 12 | println("GlobalScope.launch: ${Thread.currentThread().name}") 13 | } 14 | launch(Dispatchers.Default) { 15 | println(Thread.currentThread().name) 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/6_Instance_Checks.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | doCoolStuff(Batman()) 3 | doCoolStuff(Superman()) 4 | } 5 | 6 | fun doCoolStuff(s: Superhero) { 7 | when (s) { 8 | is Superman -> s.fly() 9 | is Batman -> s.callRobin() 10 | else -> println("Unknown superhero") 11 | } 12 | } 13 | 14 | interface Superhero 15 | class Batman : Superhero { 16 | fun callRobin() { 17 | println("To the Bat-pole, Robin!") 18 | } 19 | } 20 | 21 | class Superman : Superhero { 22 | fun fly() { 23 | println("Up, up and away!") 24 | } 25 | } -------------------------------------------------------------------------------- /Chapter05/src/main/kotlin/4_FunctionsAsValues.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val multiplyFunction = generateMultiply() 3 | println(multiplyFunction(3, 4)) 4 | 5 | mathInvoker(5, 6, multiplyFunction) 6 | 7 | mathInvoker(7, 8) { x, y -> 8 | x * y 9 | } 10 | 11 | val squareAnonymous = fun(x: Int) = x * x 12 | val squareLambda = { x: Int -> x * x } 13 | } 14 | 15 | fun mathInvoker(x: Int, y: Int, mathFunction: (Int, Int) -> Int) { 16 | println(mathFunction(x, y)) 17 | } 18 | 19 | 20 | fun generateMultiply(): (Int, Int) -> Int { 21 | return { x: Int, y: Int -> x * y } 22 | } -------------------------------------------------------------------------------- /Chapter08/src/main/kotlin/9_Mutex.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | import kotlinx.coroutines.sync.Mutex 3 | import kotlinx.coroutines.sync.withLock 4 | 5 | fun main() { 6 | runBlocking { 7 | var counter = 0 8 | val mutex = Mutex() 9 | val jobs = List(10) { 10 | async(Dispatchers.Default) { 11 | repeat(1000) { 12 | mutex.withLock { 13 | counter++ 14 | } 15 | } 16 | } 17 | } 18 | jobs.awaitAll() 19 | 20 | println(counter) 21 | } 22 | } -------------------------------------------------------------------------------- /Chapter05/src/main/kotlin/5_HigherOrderFunctions.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | 3 | val dwarfs = listOf( 4 | "Dwalin", 5 | "Balin", 6 | "Kili", 7 | "Fili", 8 | "Dori", 9 | "Nori", 10 | "Ori", 11 | "Oin", 12 | "Gloin", 13 | "Bifur", 14 | "Bofur", 15 | "Bombur", 16 | "Thorin" 17 | ) 18 | for (d in dwarfs) { 19 | println(d) 20 | } 21 | 22 | dwarfs.forEach { d -> 23 | println(d) 24 | } 25 | 26 | dwarfs.forEach { 27 | println(it) 28 | } 29 | 30 | dwarfs.forEach(::println) 31 | } -------------------------------------------------------------------------------- /Chapter03/src/main/kotlin/7_Proxy.kt: -------------------------------------------------------------------------------- 1 | import java.net.URL 2 | 3 | 4 | fun main() { 5 | val cat = CatImage( 6 | "https://i.chzbgr.com/full/9026714368/hBB09ABBE/i-will-has-attention", 7 | "https://i.chzbgr.com/full/9026714368/hBB09ABBE/i-will-has-attention" 8 | ) 9 | 10 | println(cat.image.size) 11 | println(cat.image.size) 12 | } 13 | 14 | data class CatImage( 15 | val thumbnailUrl: String, 16 | val url: String 17 | ) { 18 | val image: ByteArray by lazy { 19 | println("Fetching image, please wait") 20 | // Read image as bytes 21 | URL(url).readBytes() 22 | } 23 | } -------------------------------------------------------------------------------- /Chapter06/src/main/kotlin/6_Timeouts.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | import kotlin.random.Random 3 | 4 | fun main() = runBlocking { 5 | val coroutine = async { 6 | withTimeout(500) { 7 | try { 8 | val time = Random.nextLong(1000) 9 | println("It will take me $time to do") 10 | delay(time) 11 | println("Returning profile") 12 | "Profile" 13 | } catch (e: TimeoutCancellationException) { 14 | e.printStackTrace() 15 | } 16 | } 17 | } 18 | 19 | println("Result: ${coroutine.await()}") 20 | } -------------------------------------------------------------------------------- /Chapter08/src/main/kotlin/1_Deferred_value.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | import kotlin.random.Random 3 | 4 | fun main() { 5 | runBlocking { 6 | val value = valueAsync() 7 | println(value.await()) 8 | } 9 | } 10 | 11 | suspend fun valueAsync(): Deferred = coroutineScope { 12 | val deferred = CompletableDeferred() 13 | launch { 14 | delay(100) 15 | if (Random.nextBoolean()) { 16 | deferred.complete("OK") 17 | } else { 18 | deferred.completeExceptionally( 19 | RuntimeException() 20 | ) 21 | } 22 | } 23 | deferred 24 | } -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/14_Explicit_Asynchronicity.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.CoroutineScope 2 | import kotlinx.coroutines.async 3 | import kotlinx.coroutines.delay 4 | import kotlinx.coroutines.runBlocking 5 | 6 | fun main() { 7 | runBlocking { 8 | // Prints DeferredCoroutine{Active} 9 | println("${getResult()}") 10 | 11 | // Prints "OK" 12 | println(getResultAsync().await()) 13 | } 14 | } 15 | 16 | // This will produce a warning 17 | fun CoroutineScope.getResult() = async { 18 | delay(100) 19 | "OK" 20 | } 21 | 22 | fun CoroutineScope.getResultAsync() = async { 23 | delay(100) 24 | "OK" 25 | } -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/9_ADT.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val tree = Node( 3 | 1, 4 | Empty, 5 | Node( 6 | 2, 7 | Node(3) 8 | ) 9 | ) 10 | 11 | println(tree) 12 | println(tree.sum()) 13 | } 14 | 15 | sealed interface Tree 16 | 17 | object Empty : Tree { 18 | override fun toString() = "Empty" 19 | } 20 | 21 | data class Node( 22 | val value: T, 23 | val left: Tree = Empty, 24 | val right: Tree = Empty 25 | ) : Tree 26 | 27 | fun Tree.sum(): Long = when (this) { 28 | Empty -> 0 29 | is Node -> value + left.sum() + right.sum() 30 | } 31 | -------------------------------------------------------------------------------- /Chapter05/src/main/kotlin/8_Memoisation.kt: -------------------------------------------------------------------------------- 1 | fun summarizer(): (Set) -> Double { 2 | val resultsCache = mutableMapOf, Double>() 3 | 4 | return { numbers: Set -> 5 | resultsCache.computeIfAbsent(numbers, ::sum) 6 | } 7 | } 8 | 9 | fun sum(numbers: Set): Double { 10 | println("Computing") 11 | return numbers.sumByDouble { it.toDouble() } 12 | } 13 | 14 | fun main() { 15 | val input = listOf( 16 | setOf(1, 2, 3), 17 | setOf(3, 1, 2), 18 | setOf(2, 3, 1), 19 | setOf(4, 5, 6) 20 | ) 21 | 22 | val summarizer = summarizer() 23 | 24 | input.forEach { 25 | println(summarizer(it)) 26 | } 27 | } -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/1_Let.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val clintEastwoodQuotes = mapOf( 3 | "The Good, The Bad, The Ugly" to "Every gun makes its own tune.", 4 | "A Fistful Of Dollars" to "My mistake: four coffins." 5 | ) 6 | val quote = clintEastwoodQuotes["Unforgiven"] 7 | 8 | if (quote != null) { 9 | println(quote) 10 | } 11 | 12 | // There is a movie with that name, so let will execute the block 13 | clintEastwoodQuotes["A Fistful Of Dollars"]?.let { 14 | println(it) 15 | } 16 | 17 | // Nothing will be printed, since there's no such movie 18 | clintEastwoodQuotes["Unforgiven"]?.let { 19 | println(it) 20 | } 21 | } -------------------------------------------------------------------------------- /Chapter08/src/main/kotlin/5_Fan_Out.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | import kotlinx.coroutines.channels.ReceiveChannel 3 | import kotlinx.coroutines.channels.produce 4 | 5 | fun main() { 6 | runBlocking { 7 | val workChannel = generateWork() 8 | 9 | val workers = List(10) { id -> 10 | doWork(id, workChannel) 11 | } 12 | } 13 | } 14 | 15 | fun CoroutineScope.generateWork() = produce { 16 | for (i in 1..10_000) { 17 | send("page$i") 18 | } 19 | close() 20 | } 21 | 22 | private fun CoroutineScope.doWork( 23 | id: Int, 24 | channel: ReceiveChannel 25 | ) = launch(Dispatchers.Default) { 26 | for (p in channel) { 27 | println("Worker $id processed $p") 28 | } 29 | } -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/13_Dealing_with_Null.kt: -------------------------------------------------------------------------------- 1 | import kotlin.random.Random 2 | 3 | fun main() { 4 | // Will return "String" half of the time and null the other half 5 | val stringOrNull: String? = if (Random.nextBoolean()) "String" else null 6 | 7 | 8 | // Java-way check 9 | if (stringOrNull != null) { 10 | println(stringOrNull.length) 11 | } 12 | 13 | val alwaysLength = stringOrNull?.length ?: 0 14 | 15 | val response: Response? = Response(UserProfile(null, null)) 16 | println(response?.profile?.firstName?.length) 17 | } 18 | 19 | data class Response( 20 | val profile: UserProfile? 21 | ) 22 | 23 | data class UserProfile( 24 | val firstName: String?, 25 | val lastName: String? 26 | ) 27 | 28 | -------------------------------------------------------------------------------- /Chapter02/src/main/kotlin/2_FactoryMethod.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val queen = createPiece("qa5") 3 | println(queen) 4 | } 5 | 6 | interface ChessPiece { 7 | val file: Char 8 | val rank: Char 9 | } 10 | 11 | data class Pawn( 12 | override val file: Char, 13 | override val rank: Char 14 | ) : ChessPiece 15 | 16 | 17 | data class Queen( 18 | override val file: Char, 19 | override val rank: Char 20 | ) : ChessPiece 21 | 22 | fun createPiece(notation: String): ChessPiece { 23 | val (type, file, rank) = notation.toCharArray() 24 | return when (type) { 25 | 'q' -> Queen(file, rank) 26 | 'p' -> Pawn(file, rank) 27 | // ... 28 | else -> throw RuntimeException("Unknown piece: $type") 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/14_Conflate.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.delay 2 | import kotlinx.coroutines.flow.Flow 3 | import kotlinx.coroutines.flow.collect 4 | import kotlinx.coroutines.flow.conflate 5 | import kotlinx.coroutines.flow.flow 6 | import kotlinx.coroutines.runBlocking 7 | 8 | fun main() { 9 | 10 | runBlocking { 11 | val stock: Flow = flow { 12 | var i = 0 13 | while (true) { 14 | emit(++i) 15 | delay(100) 16 | } 17 | } 18 | 19 | var seconds = 0 20 | stock.conflate().collect { number -> 21 | delay(1000) 22 | seconds++ 23 | println("$seconds seconds -> received $number") 24 | } 25 | } 26 | 27 | 28 | } -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/7_Sequences_are_Lazy.kt: -------------------------------------------------------------------------------- 1 | import kotlin.system.measureTimeMillis 2 | 3 | fun main() { 4 | val numbers = (1..1_000_000).toList() 5 | 6 | println(measureTimeMillis { 7 | numbers.map { 8 | it * it 9 | }.take(1).forEach { it } 10 | }) // ~50ms 11 | 12 | println(measureTimeMillis { 13 | numbers.asSequence().map { 14 | it * it 15 | }.take(1).forEach { it } 16 | }) // ~5ms 17 | 18 | println(measureTimeMillis { 19 | numbers.map { 20 | it * it 21 | }.forEach { it } 22 | }) // ~50ms 23 | 24 | println(measureTimeMillis { 25 | numbers.asSequence().map { 26 | it * it 27 | }.forEach { it } 28 | }) // ~5ms 29 | } -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/10_Classes.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | // Creating a class with empty constructor 3 | // val player = Player() 4 | 5 | val player = Player("Roland") 6 | 7 | println(player.name) 8 | 9 | // Won't compile 10 | // player.name = "Alex" // Val cannot be reassigned 11 | 12 | // Invalid score 13 | player.score = -10 14 | } 15 | 16 | 17 | // Class with default empty constructor 18 | /* 19 | class Player { 20 | 21 | } 22 | */ 23 | 24 | class Player(name: String) { 25 | val name = name 26 | get() = field.toUpperCase() 27 | 28 | var score: Int = 0 29 | set(value) { 30 | field = if (value >= 0) { 31 | value 32 | } else { 33 | 0 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Chapter06/src/main/kotlin/2_Launch.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.GlobalScope 2 | import kotlinx.coroutines.delay 3 | import kotlinx.coroutines.launch 4 | import java.util.concurrent.CountDownLatch 5 | import java.util.concurrent.TimeUnit 6 | import java.util.concurrent.atomic.AtomicInteger 7 | 8 | fun main() { 9 | val latch = CountDownLatch(10_000) 10 | val c = AtomicInteger() 11 | val start = System.currentTimeMillis() 12 | 13 | for (i in 1..10_000) { 14 | GlobalScope.launch { 15 | c.incrementAndGet() 16 | delay(100) 17 | c.incrementAndGet() 18 | latch.countDown() 19 | } 20 | } 21 | 22 | latch.await(10, TimeUnit.SECONDS) 23 | 24 | println("Executed ${c.get() / 2} coroutines in ${System.currentTimeMillis() - start}ms") 25 | } -------------------------------------------------------------------------------- /Chapter08/src/main/kotlin/8_Unbiased_Select.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.CoroutineScope 2 | import kotlinx.coroutines.channels.produce 3 | import kotlinx.coroutines.delay 4 | import kotlinx.coroutines.runBlocking 5 | import kotlinx.coroutines.selects.selectUnbiased 6 | 7 | fun main() { 8 | runBlocking { 9 | val firstOption = fastProducer("Quick&Angry 7") 10 | val secondOption = fastProducer("Revengers: Penultimatum") 11 | 12 | delay(10) 13 | val movieToWatch = selectUnbiased { 14 | firstOption.onReceive { it } 15 | secondOption.onReceive { it } 16 | } 17 | println(movieToWatch) 18 | } 19 | } 20 | 21 | fun CoroutineScope.fastProducer( 22 | movieName: String 23 | ) = produce(capacity = 1) { 24 | send(movieName) 25 | } 26 | -------------------------------------------------------------------------------- /Chapter03/src/main/kotlin/4_Composite.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val bobaFett = StormTrooper(Rifle(), RegularLegs()) 3 | 4 | val squad = Squad(listOf(bobaFett.copy(), bobaFett.copy(), bobaFett.copy())) 5 | 6 | squad.attackRebel(1, 2) 7 | 8 | val secondSquad = Squad( 9 | bobaFett.copy(), 10 | bobaFett.copy(), 11 | bobaFett.copy() 12 | ) 13 | } 14 | 15 | class Squad(private val units: List) : Trooper { 16 | 17 | constructor(vararg units: Trooper) : this(units.toList()) 18 | 19 | override fun move(x: Long, y: Long) { 20 | for (u in units) { 21 | u.move(x, y) 22 | } 23 | } 24 | 25 | override fun attackRebel(x: Long, y: Long) { 26 | for (u in units) { 27 | u.attackRebel(x, y) 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /Chapter08/src/main/kotlin/6_Fan_In.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | import kotlinx.coroutines.channels.Channel 3 | import kotlinx.coroutines.channels.ReceiveChannel 4 | import kotlinx.coroutines.channels.consumeEach 5 | 6 | fun main() { 7 | runBlocking { 8 | val workChannel = generateWork() 9 | val resultChannel = Channel() 10 | val workers = List(10) { 11 | doWorkAsync(workChannel, resultChannel) 12 | } 13 | 14 | resultChannel.consumeEach { 15 | println(it) 16 | } 17 | } 18 | } 19 | 20 | 21 | private fun CoroutineScope.doWorkAsync( 22 | channel: ReceiveChannel, 23 | resultChannel: Channel 24 | ) = async(Dispatchers.Default) { 25 | for (p in channel) { 26 | resultChannel.send(p.repeat(2)) 27 | } 28 | } -------------------------------------------------------------------------------- /Chapter06/src/main/kotlin/5_Cancelling_Coroutines.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | fun main() = runBlocking { 4 | val cancellable = launch { 5 | try { 6 | for (i in 1..1000) { 7 | println("Cancellable: $i") 8 | yield() 9 | } 10 | } catch (e: CancellationException) { 11 | e.printStackTrace() 12 | } 13 | } 14 | 15 | val notCancellable = launch { 16 | for (i in 1..10_000) { 17 | if (i % 100 == 0) { 18 | println("Not cancellable $i") 19 | } 20 | } 21 | } 22 | 23 | println("Canceling cancellable") 24 | cancellable.cancel() 25 | println("Canceling not cancellable") 26 | notCancellable.cancel() 27 | 28 | cancellable.join() 29 | notCancellable.join() 30 | } -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/13_Buffered_Flows.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.delay 2 | import kotlinx.coroutines.flow.Flow 3 | import kotlinx.coroutines.flow.buffer 4 | import kotlinx.coroutines.flow.collect 5 | import kotlinx.coroutines.flow.flow 6 | import kotlinx.coroutines.runBlocking 7 | 8 | fun main() { 9 | 10 | runBlocking { 11 | val numbersFlow: Flow = flow { 12 | println("New subscriber!") 13 | (1..10).forEach { 14 | println("Sending $it") 15 | emit(it) 16 | } 17 | } 18 | 19 | (1..4).forEach { coroutineId -> 20 | delay(5000) 21 | numbersFlow.buffer().collect { number -> 22 | delay(1000) 23 | println("Coroutine $coroutineId received $number") 24 | } 25 | } 26 | } 27 | 28 | 29 | } -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/9_String_Interpolation.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val hero = "Batman" 3 | println("Archenemy of $hero is ${archenemy(hero)}") 4 | 5 | println("Twinkle, Twinkle Little Bat\n" + 6 | "How I wonder what you're at!\n" + 7 | "Up above the world you fly,\n" + 8 | "Like a tea tray in the sky.\n" + 9 | "Twinkle, twinkle, little bat!\n" + 10 | "How I wonder what you're at!") 11 | 12 | println("""Twinkle, Twinkle Little Bat 13 | How I wonder what you're at! 14 | Up above the world you fly, 15 | Like a tea tray in the sky. 16 | Twinkle, twinkle, little bat! 17 | How I wonder what you're at!""") 18 | 19 | println(""" 20 | Twinkle, Twinkle Little Bat 21 | How I wonder what you're at! 22 | """.trimIndent()) 23 | 24 | println(""" From " Alice's Adventures in Wonderland " """) 25 | } 26 | 27 | -------------------------------------------------------------------------------- /Chapter06/src/main/kotlin/8_Structured_Concurrency.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | import java.lang.RuntimeException 3 | import java.util.* 4 | 5 | fun main() = runBlocking { 6 | val parent = launch(Dispatchers.Default) { 7 | supervisorScope { 8 | val children = List(10) { childId -> 9 | launch { 10 | for (i in 1..1_000_000) { 11 | UUID.randomUUID() 12 | 13 | if (i % 100_000 == 0) { 14 | println("$childId - $i") 15 | yield() 16 | } 17 | if (childId == 8 && i == 300_000) { 18 | throw RuntimeException("Something bad happened") 19 | } 20 | } 21 | } 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Chapter02/src/main/kotlin/5_Prototype.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val originalUser = User("admin1", Role.ADMIN, setOf("READ", "WRITE", "DELETE")) 3 | allUsers += originalUser 4 | 5 | createUser("admin2", Role.ADMIN) 6 | 7 | println(allUsers) 8 | } 9 | 10 | 11 | enum class Role { 12 | ADMIN, 13 | SUPER_ADMIN, 14 | REGULAR_USER 15 | } 16 | 17 | data class User( 18 | val name: String, 19 | val role: Role, 20 | val permissions: Set, 21 | ) { 22 | fun hasPermission(permission: String) = permission in permissions 23 | } 24 | 25 | private val allUsers = mutableListOf() 26 | 27 | fun createUser(_name: String, role: Role) { 28 | for (u in allUsers) { 29 | if (u.role == role) { 30 | allUsers += u.copy(name = _name) 31 | return 32 | } 33 | } 34 | // Handle case that no other user with such a role exists 35 | } -------------------------------------------------------------------------------- /Chapter04/src/main/kotlin/4_Command.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val t = Trooper() 3 | 4 | t.addOrder(moveGenerator(t, 1, 1)) 5 | t.addOrder(moveGenerator(t, 2, 2)) 6 | t.addOrder(moveGenerator(t, 3, 3)) 7 | 8 | t.executeOrders() 9 | } 10 | 11 | open class Trooper { 12 | private val orders = mutableListOf() 13 | 14 | fun addOrder(order: Command) { 15 | this.orders.add(order) 16 | } 17 | 18 | fun executeOrders() { 19 | while (orders.isNotEmpty()) { 20 | val order = orders.removeFirst() 21 | order() // Compile error for now 22 | } 23 | } 24 | // More code here 25 | 26 | fun move(x: Int, y: Int) { 27 | println("Moving to $x:$y") 28 | } 29 | } 30 | 31 | typealias Command = () -> Unit 32 | 33 | val moveGenerator = fun( 34 | s: Trooper, 35 | x: Int, 36 | y: Int 37 | ): Command { 38 | return fun() { 39 | s.move(x, y) 40 | } 41 | } -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/12_Abstract_Classes.kt: -------------------------------------------------------------------------------- 1 | abstract class Moveable() { 2 | 3 | protected var x: Int = 0 4 | 5 | protected var y: Int = 0 6 | 7 | open fun move(x: Int, y: Int) { 8 | this.x = x 9 | this.y = y 10 | } 11 | 12 | fun position() = "$x $y" 13 | } 14 | 15 | open class ActivePlayer(val name: String) : Moveable(), DiceRoller 16 | 17 | class ConfusedPlayer(name: String) : ActivePlayer(name) { 18 | 19 | // move() must be declared open 20 | override fun move(x: Int, y: Int) { 21 | 22 | this.x = y // must be declared protected 23 | 24 | this.y = x // must be declared protected 25 | } 26 | 27 | } 28 | 29 | fun main() { 30 | val player = ConfusedPlayer("Alex") 31 | val diceX = player.rollDice() 32 | val diceY = player.rollDice() 33 | 34 | println("Dice rolled $diceX $diceY") 35 | player.move(diceX, diceY) 36 | 37 | println("Player at ${player.position()}") 38 | } -------------------------------------------------------------------------------- /Chapter11/src/main/kotlin/db.kt: -------------------------------------------------------------------------------- 1 | import io.vertx.core.Vertx 2 | import io.vertx.pgclient.PgConnectOptions 3 | import io.vertx.pgclient.PgPool 4 | import io.vertx.sqlclient.PoolOptions 5 | import io.vertx.sqlclient.SqlClient 6 | 7 | 8 | object Db { 9 | val username = System.getenv("DATABASE_USERNAME") ?: "cats_admin" 10 | val password = System.getenv("DATABASE_PASSWORD") ?: "abcd1234" 11 | val database = System.getenv("DATABASE_NAME") ?: "cats_db" 12 | val host = System.getenv("DATABASE_HOST") ?: "localhost" 13 | 14 | fun connect(vertx: Vertx): SqlClient { 15 | val connectOptions = PgConnectOptions() 16 | .setPort(5432) 17 | .setHost(host) 18 | .setDatabase(database) 19 | .setUser(username) 20 | .setPassword(password) 21 | 22 | val poolOptions = PoolOptions() 23 | .setMaxSize(20) 24 | 25 | return PgPool.client( 26 | vertx, 27 | connectOptions, 28 | poolOptions 29 | ) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Chapter10/src/main/kotlin/db.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.serialization.Serializable 2 | import org.jetbrains.exposed.dao.IntIdTable 3 | import org.jetbrains.exposed.sql.Database 4 | 5 | object DB { 6 | private val host = System.getenv("DB_HOST") ?: "localhost" 7 | private val port = System.getenv("DB_PORT")?.toIntOrNull() ?: 5432 8 | private val dbName = System.getenv("DB_NAME") ?: "cats_db" 9 | private val dbUser = System.getenv("DB_USER") ?: "cats_admin" 10 | private val dbPassword = System.getenv("DB_PASSWORD") ?: "abcd1234" 11 | fun connect() = Database.connect( 12 | "jdbc:postgresql://$host:$port/$dbName", 13 | driver = "org.postgresql.Driver", 14 | user = dbUser, 15 | password = dbPassword 16 | ) 17 | } 18 | 19 | object CatsTable : IntIdTable() { 20 | val name = varchar("name", 20).uniqueIndex() 21 | val age = integer("age").default(0) 22 | } 23 | 24 | @Serializable 25 | data class Cat( 26 | val id: Int, 27 | val name: String, 28 | val age: Int 29 | ) -------------------------------------------------------------------------------- /Chapter10/src/main/kotlin/server.kt: -------------------------------------------------------------------------------- 1 | import cats.CatsServiceImpl 2 | import io.ktor.application.* 3 | import io.ktor.features.* 4 | import io.ktor.response.* 5 | import io.ktor.routing.* 6 | import io.ktor.serialization.* 7 | import io.ktor.server.cio.* 8 | import io.ktor.server.engine.* 9 | import org.jetbrains.exposed.sql.SchemaUtils 10 | import org.jetbrains.exposed.sql.transactions.transaction 11 | 12 | fun main() { 13 | embeddedServer( 14 | CIO, 15 | port = 8080, 16 | module = Application::mainModule 17 | ).start(wait = true) 18 | } 19 | 20 | fun Application.mainModule() { 21 | DB.connect() 22 | 23 | transaction { 24 | SchemaUtils.create(CatsTable) 25 | } 26 | 27 | install(ContentNegotiation) { 28 | json() 29 | } 30 | val catsService = CatsServiceImpl() 31 | routing { 32 | get("/status") { 33 | call.respond(mapOf("status" to "OK")) 34 | } 35 | cats(catsService) 36 | } 37 | println("open http://localhost:8080") 38 | } 39 | 40 | -------------------------------------------------------------------------------- /Chapter04/src/main/kotlin/10_TemplateMethod.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | runSchedule(afterLunch = fun() { 3 | println("Discuss my lunch with boss' secretary") 4 | println("Read something not related to work") 5 | }, beforeLunch = { 6 | println("Look for my next trip destination") 7 | println("Read StackOverflow") 8 | }, bossHook = { println("Boss: Can we talk privately?") }) 9 | } 10 | 11 | 12 | fun runSchedule( 13 | beforeLunch: () -> Unit, 14 | afterLunch: () -> Unit, 15 | bossHook: (() -> Unit)? = fun() { println() } 16 | ) { 17 | fun arriveToWork() { 18 | println("How are you all?") 19 | } 20 | 21 | val drinkCoffee = { println("Did someone left the milk out?") } 22 | 23 | fun goToLunch() = println("I would like something italian") 24 | 25 | val goHome = fun() { 26 | println("Finally some rest") 27 | } 28 | 29 | arriveToWork() 30 | drinkCoffee() 31 | beforeLunch() 32 | goToLunch() 33 | afterLunch() 34 | bossHook?.let { it() } 35 | goHome() 36 | } -------------------------------------------------------------------------------- /Chapter11/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") version "1.6.0" 5 | } 6 | 7 | group = "me.soshin" 8 | version = "1.0-SNAPSHOT" 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | val vertxVersion = "4.1.5" 15 | dependencies { 16 | implementation("io.vertx:vertx-core:$vertxVersion") 17 | implementation("io.vertx:vertx-web:$vertxVersion") 18 | implementation("io.vertx:vertx-web-client:$vertxVersion") 19 | implementation("io.vertx:vertx-lang-kotlin:$vertxVersion") 20 | implementation("io.vertx:vertx-lang-kotlin-coroutines:$vertxVersion") 21 | implementation("io.vertx:vertx-pg-client:$vertxVersion") 22 | implementation("org.postgresql:postgresql:42.3.0") 23 | testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0") 24 | testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.0") 25 | } 26 | 27 | tasks.test { 28 | useJUnitPlatform() 29 | } 30 | 31 | tasks.withType() { 32 | kotlinOptions.jvmTarget = "1.8" 33 | } -------------------------------------------------------------------------------- /Chapter05/src/main/kotlin/7_Currying.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | println(subtract(4)(5)) 3 | 4 | val infoLogger = createLogger(LogLevel.INFO) 5 | infoLogger("Log something") 6 | } 7 | 8 | // If this is a function without currying at all 9 | fun subtract(x: Int, y: Int): Int { 10 | return x - y 11 | } 12 | 13 | // This is a complex way to implement currying 14 | /* 15 | fun subtract(x: Int): (Int) -> Int { 16 | return fun(y: Int): Int { 17 | return x - y 18 | } 19 | } 20 | */ 21 | 22 | // And it could be simplified 23 | //fun subtract(x: Int) = fun(y: Int) = x - y 24 | 25 | // Simplest way 26 | fun subtract(x: Int) = { y: Int -> x - y } 27 | 28 | 29 | enum class LogLevel { 30 | ERROR, WARNING, INFO 31 | } 32 | 33 | fun log(level: LogLevel, message: String) = 34 | println("$level: $message") 35 | 36 | val errorLog = fun(message: String) { 37 | log(LogLevel.ERROR, message) 38 | } 39 | 40 | fun createLogger(level: LogLevel): (String) -> Unit { 41 | return { message: String -> 42 | log(level, message) 43 | } 44 | } -------------------------------------------------------------------------------- /Chapter08/src/main/kotlin/7_Racing.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.CoroutineScope 2 | import kotlinx.coroutines.channels.produce 3 | import kotlinx.coroutines.delay 4 | import kotlinx.coroutines.runBlocking 5 | import kotlinx.coroutines.selects.select 6 | import kotlin.random.Random 7 | 8 | fun main() { 9 | runBlocking { 10 | while (true) { 11 | val winner = select> { 12 | preciseWeather().onReceive { preciseWeatherResult -> 13 | preciseWeatherResult 14 | } 15 | weatherToday().onReceive { weatherTodayResult -> 16 | weatherTodayResult 17 | } 18 | } 19 | println(winner) 20 | delay(1000) 21 | } 22 | } 23 | } 24 | 25 | fun CoroutineScope.preciseWeather() = produce { 26 | delay(Random.nextLong(100)) 27 | send("Precise Weather" to "+25c") 28 | } 29 | 30 | fun CoroutineScope.weatherToday() = produce { 31 | delay(Random.nextLong(100)) 32 | send("Weather Today" to "+24c") 33 | } 34 | -------------------------------------------------------------------------------- /Chapter10/src/main/kotlin/cats.kt: -------------------------------------------------------------------------------- 1 | import cats.CatsService 2 | 3 | import io.ktor.application.* 4 | import io.ktor.http.* 5 | import io.ktor.request.* 6 | import io.ktor.response.* 7 | import io.ktor.routing.* 8 | 9 | fun Routing.cats(service: CatsService) { 10 | route("/cats") { 11 | post { 12 | val parameters: Parameters = call.receiveParameters() 13 | val name = requireNotNull(parameters["name"]) 14 | val age = parameters["age"]?.toInt() ?: 0 15 | service.create(name, age) 16 | call.respond(HttpStatusCode.Created) 17 | } 18 | get { 19 | val cats = service.findAll() 20 | call.respond(cats) 21 | } 22 | get("/{id}") { 23 | val id = requireNotNull(call.parameters["id"]).toInt() 24 | 25 | val cat = service.find(id) 26 | 27 | if (cat == null) { 28 | call.respond(HttpStatusCode.NotFound) 29 | } else { 30 | call.respond(cat) 31 | } 32 | } 33 | } 34 | } 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Chapter08/src/main/kotlin/3_Scheduler.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | import java.util.concurrent.Executors 3 | import java.util.concurrent.ForkJoinPool 4 | 5 | fun main() { 6 | runBlocking { 7 | 8 | // This will use the Dispatcher from the parent coroutine 9 | launch { 10 | // Prints: main 11 | println(Thread.currentThread().name) 12 | } 13 | launch(Dispatchers.Default) { 14 | // Prints DefaultDispatcher-worker-1 15 | println(Thread.currentThread().name) 16 | } 17 | 18 | async(Dispatchers.IO) { 19 | for (i in 1..1000) { 20 | println(Thread.currentThread().name) 21 | yield() 22 | } 23 | } 24 | 25 | val myDispatcher = Executors 26 | .newFixedThreadPool(4) 27 | .asCoroutineDispatcher() 28 | 29 | val forkJoinPool = ForkJoinPool(4).asCoroutineDispatcher() 30 | 31 | repeat(1000) { 32 | launch(forkJoinPool) { 33 | println(Thread.currentThread().name) 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Chapter10/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") version "1.6.0" 5 | application 6 | kotlin("plugin.serialization") version "1.6.0" 7 | } 8 | 9 | group = "me.soshin" 10 | version = "1.0-SNAPSHOT" 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | val ktorVersion = "1.6.4" 17 | dependencies { 18 | implementation("io.ktor:ktor-server-netty:$ktorVersion") 19 | implementation("io.ktor:ktor-server-cio:$ktorVersion") 20 | implementation("io.ktor:ktor-serialization:$ktorVersion") 21 | implementation("org.jetbrains.exposed:exposed:0.17.14") 22 | implementation("org.postgresql:postgresql:42.2.24") 23 | testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0") 24 | testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.0") 25 | testImplementation("io.ktor:ktor-server-tests:$ktorVersion") 26 | } 27 | 28 | tasks.test { 29 | useJUnitPlatform() 30 | } 31 | 32 | tasks.withType() { 33 | kotlinOptions.jvmTarget = "1.8" 34 | } 35 | 36 | application { 37 | mainClassName = "ServerKt" 38 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Chapter03/src/main/kotlin/6_Flyweight.kt: -------------------------------------------------------------------------------- 1 | import java.io.File 2 | 3 | fun main() { 4 | // Flyweight allows us to create much more objects that otherwise possible 5 | val snails = List(10_000) { 6 | TansanianSnail() 7 | } 8 | } 9 | 10 | enum class Direction { 11 | LEFT, 12 | RIGHT 13 | } 14 | 15 | class TansanianSnail { 16 | val directionFacing = Direction.LEFT 17 | 18 | // This is the Flyweight we're using 19 | val sprites = SnailSprites.sprites 20 | 21 | fun getCurrentSprite(): File { 22 | return when (directionFacing) { 23 | Direction.LEFT -> sprites[0] 24 | Direction.RIGHT -> sprites[1] 25 | } 26 | } 27 | 28 | // More information about the state of a snail comes here 29 | 30 | // This may include its health, for example 31 | } 32 | 33 | object SnailSprites { 34 | val sprites = List(8) { i -> 35 | java.io.File( 36 | when (i) { 37 | 0 -> "snail-left.jpg" 38 | 1 -> "snail-right.jpg" 39 | in 2..4 -> "snail-move-left-${i - 1}.jpg" 40 | else -> "snail-move-right${(4 - i)}.jpg" 41 | } 42 | ) 43 | } 44 | } -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/12_Buffered_Channels.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.channels.actor 2 | import kotlinx.coroutines.channels.consumeEach 3 | import kotlinx.coroutines.delay 4 | import kotlinx.coroutines.runBlocking 5 | 6 | fun main() { 7 | //nonBuffered() 8 | buffered() 9 | } 10 | 11 | fun nonBuffered() { 12 | runBlocking { 13 | val actor = actor { 14 | var prev = 0L 15 | channel.consumeEach { 16 | println(it - prev) 17 | prev = it 18 | delay(100) 19 | } 20 | } 21 | 22 | repeat(10) { 23 | actor.send(System.currentTimeMillis()) 24 | } 25 | actor.close().also { println("Done sending") } 26 | } 27 | } 28 | 29 | fun buffered() { 30 | runBlocking { 31 | val actor = actor(capacity = 10) { 32 | var prev = 0L 33 | channel.consumeEach { 34 | println(it - prev) 35 | prev = it 36 | delay(100) 37 | } 38 | } 39 | 40 | repeat(10) { 41 | actor.send(System.currentTimeMillis()) 42 | } 43 | println("Done sending") 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/10_Reified_Generics.kt: -------------------------------------------------------------------------------- 1 | import kotlin.reflect.KClass 2 | 3 | fun main() { 4 | printIfSameType(Int::class, 1) // Print 1, as 1 is Int 5 | printIfSameType(Int::class, 2L) // Prints no, as 2 is Long 6 | printIfSameType(Long::class, 3L) // Prints yes, as 3 is Long 7 | 8 | printIfSameReified(1) // Print 1, as 1 is Int 9 | printIfSameReified(2L) // Prints no, as 2 is Long 10 | printIfSameReified(3L) // Prints yes, as 3 is Long 11 | 12 | val p: Pair = "a" to "b" 13 | } 14 | 15 | fun printIfSameType(clazz: KClass, a: Number) { 16 | if (clazz.isInstance(a)) { 17 | println("Yes") 18 | } else { 19 | println("No") 20 | } 21 | } 22 | 23 | inline fun printIfSameReified(a: Number) { 24 | if (a is T) { 25 | println("Yes") 26 | } else { 27 | println("No") 28 | } 29 | } 30 | 31 | inline fun printList(list: List) { 32 | when { 33 | 1 is T -> println("This is a list of Ints") 34 | 1L is T -> println("This is a list of Longs") 35 | else -> println("This is a list of something else") 36 | } 37 | println(list) 38 | } -------------------------------------------------------------------------------- /Chapter04/src/main/kotlin/6_Interpreter.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | 3 | val sql = select("name, age") { 4 | from("users") { 5 | where("age > 25") 6 | } // Closes from 7 | } // Closes select 8 | 9 | println(sql) // "SELECT name, age FROM users WHERE age > 25" 10 | } 11 | 12 | fun select(columns: String, from: SelectClause.() -> Unit): 13 | SelectClause { 14 | return SelectClause(columns).apply(from) 15 | } 16 | 17 | class SelectClause(private val columns: String) { 18 | private lateinit var from: FromClause 19 | fun from( 20 | table: String, 21 | where: FromClause.() -> Unit 22 | ): FromClause { 23 | this.from = FromClause(table) 24 | return this.from.apply(where) 25 | } 26 | 27 | override fun toString() = "SELECT $columns $from" 28 | } 29 | 30 | class FromClause(private val table: String) { 31 | private lateinit var where: WhereClause 32 | 33 | fun where(conditions: String) = this.apply { 34 | where = WhereClause(conditions) 35 | } 36 | 37 | override fun toString() = "FROM $table $where" 38 | } 39 | 40 | class WhereClause(private val conditions: String) { 41 | override fun toString() = "WHERE $conditions" 42 | } -------------------------------------------------------------------------------- /Chapter04/src/main/kotlin/8_Memento.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val michael = Manager() 3 | michael.think("Need to implement Coconut Cannon") 4 | michael.think("Should get some coffee") 5 | val memento = michael.saveThatThought() 6 | with(michael) { 7 | think("Or maybe tea?") 8 | think("No, actually, let's implement Pineapple Launcher") 9 | } 10 | michael.printThoughts() 11 | michael.`what was I thinking back then?`(memento) 12 | michael.printThoughts() 13 | } 14 | 15 | class Manager { 16 | private var thoughts = mutableListOf() 17 | 18 | fun printThoughts() { 19 | println(thoughts) 20 | } 21 | 22 | inner class Memory(private val mindState: List) { 23 | fun restore() { 24 | thoughts = mindState.toMutableList() 25 | } 26 | } 27 | 28 | fun saveThatThought(): Memory { 29 | return Memory(thoughts.toList()) 30 | } 31 | 32 | fun `what was I thinking back then?`(memory: Memory) { 33 | memory.restore() 34 | } 35 | 36 | fun think(thought: String) { 37 | thoughts.add(thought) 38 | if (thoughts.size > 2) { 39 | thoughts.removeFirst() 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /Chapter07/src/main/kotlin/8_Flows.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.Dispatchers 2 | import kotlinx.coroutines.delay 3 | import kotlinx.coroutines.flow.Flow 4 | import kotlinx.coroutines.flow.collect 5 | import kotlinx.coroutines.flow.flow 6 | import kotlinx.coroutines.launch 7 | import kotlinx.coroutines.runBlocking 8 | import java.lang.RuntimeException 9 | 10 | fun main() { 11 | 12 | runBlocking { 13 | val numbersFlow: Flow = flow { 14 | println("New subscriber!") 15 | (1..10).forEach { 16 | println("Sending $it") 17 | emit(it) 18 | if (it == 9) { 19 | throw RuntimeException() 20 | } 21 | } 22 | } 23 | 24 | (1..4).forEach { coroutineId -> 25 | delay(5000) 26 | launch(Dispatchers.Default) { 27 | try { 28 | numbersFlow.collect { number -> 29 | delay(1000) 30 | println("Coroutine $coroutineId received $number") 31 | } 32 | } catch (e: Exception) { 33 | println("Coroutine $coroutineId got an error") 34 | } 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Chapter08/src/main/kotlin/10_Sidekick_Channel.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.channels.actor 2 | import kotlinx.coroutines.delay 3 | import kotlinx.coroutines.launch 4 | import kotlinx.coroutines.runBlocking 5 | import kotlinx.coroutines.selects.select 6 | 7 | fun main() { 8 | runBlocking { 9 | val batman = actor { 10 | for (c in channel) { 11 | println("Batman is beating some sense into $c") 12 | delay(100) 13 | } 14 | } 15 | 16 | val robin = actor { 17 | for (c in channel) { 18 | println("Robin is beating some sense into $c") 19 | delay(250) 20 | } 21 | } 22 | 23 | val epicFight = launch { 24 | for (villain in listOf("Jocker", "Bane", "Penguin", "Riddler", "Killer Croc")) { 25 | val result = select> { 26 | batman.onSend(villain) { 27 | "Batman" to villain 28 | } 29 | robin.onSend(villain) { 30 | "Robin" to villain 31 | } 32 | } 33 | delay(90) 34 | println(result) 35 | } 36 | } 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /Chapter06/src/main/kotlin/1_Threads.kt: -------------------------------------------------------------------------------- 1 | import java.util.concurrent.CountDownLatch 2 | import kotlin.concurrent.thread 3 | 4 | fun main() { 5 | startingThreads() 6 | threadRace() 7 | synchronisingThreads() 8 | } 9 | 10 | fun synchronisingThreads() { 11 | var counter = 0 12 | val latch = CountDownLatch(100_000) 13 | repeat(100) { 14 | thread { 15 | repeat(1000) { 16 | synchronized(latch) { 17 | counter++ 18 | latch.countDown() 19 | } 20 | } 21 | } 22 | } 23 | 24 | latch.await() 25 | 26 | println("Counter $counter") 27 | } 28 | 29 | fun threadRace() { 30 | var counter = 0 31 | val latch = CountDownLatch(100_000) 32 | repeat(100) { 33 | thread { 34 | repeat(1000) { 35 | //synchronized(latch) { 36 | counter++ 37 | latch.countDown() 38 | //} 39 | } 40 | } 41 | } 42 | 43 | latch.await() 44 | 45 | println("Counter $counter") 46 | } 47 | 48 | fun startingThreads() { 49 | repeat(2) { t -> 50 | thread { 51 | for (i in 1..100) { 52 | println("T$t: $i") 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Chapter11/src/main/kotlin/cats.kt: -------------------------------------------------------------------------------- 1 | import io.vertx.core.json.JsonObject 2 | import io.vertx.kotlin.coroutines.CoroutineVerticle 3 | import io.vertx.kotlin.coroutines.await 4 | import io.vertx.sqlclient.Tuple 5 | import kotlinx.coroutines.launch 6 | 7 | class CatsVerticle : CoroutineVerticle() { 8 | override suspend fun start() { 9 | val db = Db.connect(vertx) 10 | vertx.eventBus().consumer("cats:delete") { req -> 11 | launch { 12 | val id = req.body() 13 | db.preparedQuery("DELETE FROM cats WHERE ID = $1") 14 | .execute(Tuple.of(id)).await() 15 | req.reply(null) 16 | } 17 | } 18 | vertx.eventBus().consumer("cats:update") { req -> 19 | launch { 20 | val body = req.body() 21 | db.preparedQuery("UPDATE cats SET name = $1, age = $2 WHERE ID = $3") 22 | .execute( 23 | Tuple.of( 24 | body.getString("name"), 25 | body.getInteger("age"), 26 | body.getInteger("id") 27 | ) 28 | ).await() 29 | req.reply(body.getInteger("id")) 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /Chapter02/src/main/kotlin/4_Builder.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val mail = MailBuilder() 3 | .recepients(listOf("hello@world.com")) 4 | .message("Hello") 5 | .build() 6 | 7 | println(mail.to) 8 | println(mail.cc) 9 | println(mail.message) 10 | } 11 | 12 | class MailBuilder { 13 | private var recepients: List = listOf() 14 | private var cc: List = listOf() 15 | private var title: String = "" 16 | private var message: String = "" 17 | private var important: Boolean = false 18 | 19 | class Mail internal constructor( 20 | val to: List, 21 | val cc: List?, 22 | val title: String?, 23 | val message: String?, 24 | val important: Boolean 25 | ) 26 | 27 | fun build(): Mail { 28 | if (recepients.isEmpty()) { 29 | throw RuntimeException("To property is empty") 30 | } 31 | 32 | return Mail(recepients, cc, title, message, important) 33 | } 34 | 35 | fun message(message: String = ""): MailBuilder { 36 | this.message = message 37 | return this 38 | } 39 | 40 | fun recepients(recepients: List): MailBuilder { 41 | this.recepients = recepients 42 | return this 43 | } 44 | 45 | // More functions to be implemented here 46 | } -------------------------------------------------------------------------------- /Chapter04/src/main/kotlin/1_Strategy.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val hero = OurHero() 3 | hero.shoot() 4 | hero.currentWeapon = Weapons::banana 5 | hero.shoot() 6 | } 7 | 8 | class OurHero { 9 | private var direction = Direction.LEFT 10 | private var x: Int = 42 11 | private var y: Int = 173 12 | 13 | var currentWeapon = Weapons::peashooter 14 | 15 | val shoot = fun() { 16 | currentWeapon(x, y, direction) 17 | } 18 | 19 | } 20 | 21 | enum class Direction { 22 | LEFT, RIGHT 23 | } 24 | 25 | data class Projectile( 26 | private var x: Int, 27 | private var y: Int, 28 | private var direction: Direction 29 | ) 30 | 31 | interface Weapon { 32 | fun shoot( 33 | x: Int, 34 | y: Int, 35 | direction: Direction 36 | ): Projectile 37 | } 38 | 39 | object Weapons { 40 | // Flies straight 41 | fun peashooter(x: Int, y: Int, direction: Direction): Projectile { 42 | println("It's a peashooter") 43 | return Projectile(x, y, direction) 44 | } 45 | 46 | // Returns back after reaching end of the screen 47 | fun banana(x: Int, y: Int, direction: Direction): Projectile { 48 | println("It's a banana") 49 | return Projectile(x, y, direction) 50 | } 51 | 52 | // Explodes on contact 53 | fun pomegranate(x: Int, y: Int, direction: Direction): Projectile { 54 | println("It's a pomegranate") 55 | return Projectile(x, y, direction) 56 | } 57 | } 58 | 59 | 60 | -------------------------------------------------------------------------------- /Chapter09/src/main/kotlin/16_Sealead_classes.kt: -------------------------------------------------------------------------------- 1 | import kotlin.random.Random 2 | 3 | fun main() { 4 | var order: PizzaOrderStatus = OrderReceived(Random.nextInt()) 5 | println(order) 6 | order = order.nextStatus() 7 | println(order) 8 | order = order.nextStatus() 9 | println(order) 10 | order = order.nextStatus() 11 | println(order) 12 | } 13 | 14 | 15 | // Java-like code that uses enum to represent State 16 | /*enum class PizzaOrderStatus { 17 | ORDER_RECEIVED, PIZZA_BEING_MADE, OUT_FOR_DELIVERY, COMPLETED; 18 | 19 | fun nextStatus(): PizzaOrderStatus { 20 | return when (this) { 21 | ORDER_RECEIVED -> PIZZA_BEING_MADE 22 | PIZZA_BEING_MADE -> OUT_FOR_DELIVERY 23 | OUT_FOR_DELIVERY -> COMPLETED 24 | COMPLETED -> COMPLETED 25 | } 26 | } 27 | }*/ 28 | 29 | sealed class PizzaOrderStatus(protected val orderId: Int) { 30 | abstract fun nextStatus(): PizzaOrderStatus 31 | } 32 | 33 | class OrderReceived(orderId: Int) : PizzaOrderStatus(orderId) { 34 | override fun nextStatus() = PizzaBeingMade(orderId) 35 | } 36 | 37 | class PizzaBeingMade(orderId: Int) : PizzaOrderStatus(orderId) { 38 | override fun nextStatus() = OutForDelivery(orderId) 39 | } 40 | 41 | class OutForDelivery(orderId: Int) : PizzaOrderStatus(orderId) { 42 | override fun nextStatus() = Completed(orderId) 43 | } 44 | 45 | class Completed(orderId: Int) : PizzaOrderStatus(orderId) { 46 | override fun nextStatus() = this 47 | } -------------------------------------------------------------------------------- /Chapter05/src/main/kotlin/9_Tail_Recursion.kt: -------------------------------------------------------------------------------- 1 | tailrec fun sumRec(i: Int, sum: Long, numbers: List): Long { 2 | return if (i == numbers.size) { 3 | return sum 4 | } else { 5 | sumRec(i + 1, numbers[i] + sum, numbers) 6 | } 7 | } 8 | 9 | fun main() { 10 | 11 | val numbers = List(1_000_000) { it } 12 | 13 | println(sumRec(0, 0, numbers)) 14 | 15 | val res = mergeSort(numbers.shuffled()) 16 | 17 | println(res.take(100)) 18 | } 19 | 20 | tailrec fun mergeSort(numbers: List): List { 21 | return when { 22 | numbers.size <= 1 -> numbers 23 | numbers.size == 2 -> { 24 | return if (numbers[0] < numbers[1]) { 25 | numbers 26 | } else { 27 | listOf(numbers[1], numbers[0]) 28 | } 29 | } 30 | else -> { 31 | val left = mergeSort(numbers.slice(0..numbers.size / 2)) 32 | val right = mergeSort(numbers.slice(numbers.size / 2 + 1 until numbers.size)) 33 | return merge(left, right) 34 | } 35 | } 36 | } 37 | 38 | fun merge(left: List, right: List): List { 39 | val result = mutableListOf() 40 | var l = 0 41 | var r = 0 42 | while (l < left.size && r < right.size) { 43 | result += if (left[l] < right[r]) { 44 | left[l++] 45 | } else { 46 | right[r++] 47 | } 48 | } 49 | while (l < left.size) { 50 | result += left[l++] 51 | } 52 | while (r < right.size) { 53 | result += right[r++] 54 | } 55 | return result 56 | } -------------------------------------------------------------------------------- /Chapter02/src/main/kotlin/3_AbstractFactory.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val environment = Parser.server(listOf("port: 8080", "environment: production")) 3 | println(environment) 4 | } 5 | 6 | 7 | class Parser { 8 | 9 | companion object { 10 | fun server(propertyStrings: List): ServerConfiguration { 11 | val parsedProperties = mutableListOf() 12 | for (p in propertyStrings) { 13 | parsedProperties += property(p) 14 | } 15 | 16 | return ServerConfigurationImpl(parsedProperties) 17 | } 18 | 19 | fun property(prop: String): Property { 20 | val (name, value) = prop.split(":") 21 | 22 | return when (name) { 23 | "port" -> IntProperty(name, value.trim().toInt()) 24 | "environment" -> StringProperty(name, value.trim()) 25 | else -> throw RuntimeException("Unknown property: $name") 26 | } 27 | } 28 | } 29 | } 30 | 31 | 32 | interface Property { 33 | 34 | val name: String 35 | 36 | val value: Any 37 | 38 | } 39 | 40 | 41 | interface ServerConfiguration { 42 | 43 | val properties: List 44 | 45 | } 46 | 47 | data class ServerConfigurationImpl( 48 | 49 | override val properties: List 50 | 51 | ) : ServerConfiguration 52 | 53 | data class StringProperty( 54 | 55 | override val name: String, 56 | 57 | override val value: String 58 | 59 | ) : Property 60 | 61 | data class IntProperty( 62 | 63 | override val name: String, 64 | 65 | override val value: Int 66 | 67 | ) : Property -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/8_Control_Flow.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | 3 | ifs() 4 | 5 | whens() 6 | 7 | loops() 8 | } 9 | 10 | fun loops() { 11 | for (c in "Word") { 12 | 13 | println(c) 14 | 15 | } 16 | 17 | val jokers = listOf("Heath Ledger", "Joaquin Phoenix", "Jack Nicholson") 18 | 19 | for (j in jokers) { 20 | println(j) 21 | } 22 | 23 | for (i in 0..9) { 24 | println(i) 25 | } 26 | 27 | for (i in 0 until 10) { 28 | println("for until $i") // Same output as the previous loop 29 | } 30 | 31 | for (i in 9 downTo 0) { 32 | println("for downTo $i") // 9, 8, 7... 33 | } 34 | 35 | var x = 0 36 | while (x < 10) { 37 | x++ 38 | println("while $x") 39 | } 40 | 41 | x = 5 42 | do { 43 | println("do while $x") 44 | x-- 45 | } while (x > 0) 46 | } 47 | 48 | fun whens() { 49 | println(archenemy("Batman")) 50 | println(archenemy("Wolverine")) 51 | } 52 | 53 | fun ifs() { 54 | println(getUnixSocketPolling(true)) 55 | 56 | println(getUnixSocketPolling(false)) 57 | } 58 | 59 | fun getUnixSocketPolling(isBsd: Boolean): String { 60 | return if (isBsd) { 61 | "kqueue" 62 | } else { 63 | "epoll" 64 | } 65 | } 66 | 67 | // Shorter version: 68 | /* 69 | fun getUnixSocketPolling(isBsd: Boolean): String = 70 | if (isBsd) "kqueue" else "epoll"*/ 71 | 72 | 73 | 74 | fun archenemy(heroName: String) = when (heroName) { 75 | "Batman" -> "Joker" 76 | "Superman" -> "Lex Luthor" 77 | "Spider-Man" -> "Green Goblin" 78 | else -> "Sorry, no idea" 79 | } -------------------------------------------------------------------------------- /Chapter03/src/main/kotlin/3_Bridge.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val stormTrooper = StormTrooper(Rifle(), RegularLegs()) 3 | val flameTrooper = StormTrooper(Flamethrower(), RegularLegs()) 4 | val scoutTrooper = StormTrooper(Rifle(), AthleticLegs()) 5 | 6 | println(listOf(stormTrooper, flameTrooper, scoutTrooper)) 7 | } 8 | 9 | interface Trooper { 10 | fun move(x: Long, y: Long) 11 | 12 | fun attackRebel(x: Long, y: Long) 13 | } 14 | 15 | data class StormTrooper( 16 | private val weapon: Weapon, 17 | private val legs: Legs 18 | ) : Trooper { 19 | override fun move(x: Long, y: Long) { 20 | legs.move(x, y) 21 | } 22 | 23 | override fun attackRebel(x: Long, y: Long) { 24 | println("Attacking") 25 | weapon.attack(x, y) 26 | } 27 | } 28 | 29 | typealias PointsOfDamage = Long 30 | typealias Meters = Int 31 | 32 | interface Weapon { 33 | fun attack(x: Long, y: Long): PointsOfDamage 34 | } 35 | 36 | interface Legs { 37 | fun move(x: Long, y: Long): Meters 38 | } 39 | 40 | const val RIFLE_DAMAGE = 3L 41 | const val REGULAR_SPEED: Meters = 1 42 | 43 | class Rifle : Weapon { 44 | override fun attack(x: Long, y: Long) = RIFLE_DAMAGE 45 | } 46 | 47 | class Flamethrower : Weapon { 48 | override fun attack(x: Long, y: Long) = RIFLE_DAMAGE * 2 49 | } 50 | 51 | 52 | class Batton : Weapon { 53 | override fun attack(x: Long, y: Long) = RIFLE_DAMAGE * 3 54 | } 55 | 56 | class RegularLegs : Legs { 57 | override fun move(x: Long, y: Long) = REGULAR_SPEED 58 | } 59 | 60 | class AthleticLegs : Legs { 61 | override fun move(x: Long, y: Long) = REGULAR_SPEED * 2 62 | } 63 | 64 | -------------------------------------------------------------------------------- /Chapter04/src/main/kotlin/3_State.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val snail = Snail() 3 | snail.seeHero() 4 | snail.getHit(1) 5 | snail.getHit(10) 6 | } 7 | 8 | interface WhatCanHappen { 9 | fun seeHero() 10 | 11 | fun getHit(pointsOfDamage: Int) 12 | 13 | fun calmAgain() 14 | } 15 | 16 | class Snail : WhatCanHappen { 17 | private var healthPoints = 10 18 | private var mood: Mood = Still 19 | 20 | override fun seeHero() { 21 | mood = when (mood) { 22 | is Still -> { 23 | println("Aggressive") 24 | Aggressive 25 | } 26 | else -> { 27 | println("No change") 28 | mood 29 | } 30 | } 31 | } 32 | 33 | override fun getHit(pointsOfDamage: Int) { 34 | println("Hit for $pointsOfDamage points") 35 | healthPoints -= pointsOfDamage 36 | 37 | println("Health: $healthPoints") 38 | mood = when { 39 | (healthPoints <= 0) -> { 40 | println("Dead") 41 | Dead 42 | } 43 | mood is Aggressive -> { 44 | println("Retreating") 45 | Retreating 46 | } 47 | else -> { 48 | println("No change") 49 | mood 50 | } 51 | } 52 | } 53 | 54 | override fun calmAgain() { 55 | } 56 | } 57 | 58 | sealed class Mood { 59 | // Some abstract methods here, like draw(), for example 60 | } 61 | 62 | object Still : Mood() 63 | 64 | object Aggressive : Mood() 65 | 66 | object Retreating : Mood() 67 | 68 | object Dead : Mood() -------------------------------------------------------------------------------- /Chapter04/src/main/kotlin/11_Observable.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val catTheConductor = Cat() 3 | 4 | val bat = Bat() 5 | val dog = Dog() 6 | val turkey = Turkey() 7 | 8 | catTheConductor.joinChoir(bat::screech) 9 | catTheConductor.joinChoir(dog::howl) 10 | catTheConductor.joinChoir(dog::bark) 11 | catTheConductor.joinChoir(turkey::gobble) 12 | 13 | catTheConductor.conduct() 14 | catTheConductor.conduct() 15 | } 16 | 17 | class Bat { 18 | fun screech() { 19 | println("Eeeeeee") 20 | } 21 | } 22 | 23 | class Turkey { 24 | fun gobble() { 25 | println("Gob-gob") 26 | } 27 | } 28 | 29 | class Dog { 30 | fun bark() { 31 | println("Woof") 32 | } 33 | 34 | fun howl() { 35 | println("Auuuu") 36 | } 37 | } 38 | 39 | class Cat { 40 | private val participants = mutableMapOf<() -> Unit, () -> Unit>() 41 | 42 | fun joinChoir(whatToCall: () -> Unit) { 43 | participants[whatToCall] = whatToCall 44 | } 45 | 46 | fun leaveChoir(whatNotToCall: () -> Unit) { 47 | participants.remove(whatNotToCall) 48 | } 49 | 50 | fun conduct() { 51 | for (p in participants.values) { 52 | p() 53 | } 54 | } 55 | } 56 | 57 | typealias Times = Int 58 | 59 | enum class SoundPitch { HIGH, LOW } 60 | interface Message { 61 | val repeat: Times 62 | val pitch: SoundPitch 63 | } 64 | 65 | 66 | data class LowMessage(override val repeat: Times) : Message { 67 | override val pitch = SoundPitch.LOW 68 | } 69 | 70 | data class HighMessage(override val repeat: Times) : Message { 71 | override val pitch = SoundPitch.HIGH 72 | } 73 | 74 | -------------------------------------------------------------------------------- /Chapter10/src/main/kotlin/cats/CatService.kt: -------------------------------------------------------------------------------- 1 | package cats 2 | 3 | import Cat 4 | import CatsTable 5 | import org.jetbrains.exposed.dao.EntityID 6 | import org.jetbrains.exposed.sql.insertAndGetId 7 | import org.jetbrains.exposed.sql.select 8 | import org.jetbrains.exposed.sql.selectAll 9 | import org.jetbrains.exposed.sql.transactions.transaction 10 | 11 | interface CatsService { 12 | fun findAll(): List 13 | fun find(id: Int): Cat? 14 | fun create(name: String, age: Int): EntityID 15 | } 16 | 17 | class CatsServiceImpl : CatsService { 18 | override fun findAll(): List { 19 | return transaction { 20 | CatsTable.selectAll().map { row -> 21 | Cat( 22 | row[CatsTable.id].value, 23 | row[CatsTable.name], 24 | row[CatsTable.age] 25 | ) 26 | } 27 | } 28 | } 29 | 30 | override fun find(id: Int): Cat? { 31 | return transaction { 32 | val row = CatsTable.select { 33 | CatsTable.id.eq(id) 34 | }.firstOrNull() 35 | 36 | if (row != null) { 37 | Cat( 38 | row[CatsTable.id].value, 39 | row[CatsTable.name], 40 | row[CatsTable.age] 41 | ) 42 | } 43 | else { 44 | null 45 | } 46 | } 47 | } 48 | 49 | override fun create(name: String, age: Int): EntityID { 50 | return transaction { 51 | CatsTable.insertAndGetId { cat -> 52 | cat[CatsTable.name] = name 53 | cat[CatsTable.age] = age 54 | } 55 | } 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /Chapter01/src/main/kotlin/7_Data_Structures.kt: -------------------------------------------------------------------------------- 1 | import java.util.* 2 | 3 | fun main(args: Array) { 4 | lists() 5 | 6 | sets() 7 | 8 | maps() 9 | 10 | arrays() 11 | 12 | println(args.joinToString(", ")) 13 | } 14 | 15 | fun arrays() { 16 | val musketeers: Array = arrayOf("Athos", "Porthos", "Aramis") 17 | 18 | println(musketeers) 19 | 20 | listOf(1, 2, 3, 5).toTypedArray() 21 | } 22 | 23 | fun maps() { 24 | val movieBatmans = mapOf( 25 | 26 | "Batman Returns" to "Michael Keaton", 27 | 28 | "Batman Forever" to "Val Kilmer", 29 | 30 | "Batman & Robin" to "George Clooney" 31 | 32 | ) 33 | 34 | println(movieBatmans["Batman Returns"]) 35 | 36 | println("Batman Begins" !in movieBatmans) 37 | 38 | // Mutable map that is sorted by its keys 39 | 40 | val treeMap = TreeMap( 41 | 42 | mapOf( 43 | 44 | "Practical Pig" to "bricks", 45 | 46 | "Fifer" to "straw", 47 | 48 | "Fiddler" to "sticks" 49 | 50 | ) 51 | 52 | ) 53 | 54 | println(treeMap.keys) 55 | } 56 | 57 | fun sets() { 58 | val footballChampions = setOf("France", "Germany", "Spain", "Italy", "Brazil", "France", "Brazil", "Germany") 59 | 60 | println(footballChampions) 61 | 62 | println("Israel" in footballChampions) // false 63 | 64 | println("Italy" in footballChampions) // true 65 | } 66 | 67 | fun lists() { 68 | val hobbits = listOf("Frodo", "Sam", "Pippin", "Merry") 69 | 70 | println(hobbits[1]) 71 | 72 | // Won't compile 73 | // hobbits[0] = "Bilbo" // Unresolved reference 74 | 75 | val editableHobbits = mutableListOf("Frodo", "Sam", "Pippin", "Merry") 76 | 77 | editableHobbits.add("Bilbo") 78 | } 79 | -------------------------------------------------------------------------------- /Chapter04/src/main/kotlin/2_Iterator.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val platoon = Squad( 3 | Trooper(), 4 | Squad( 5 | Trooper(), 6 | ), 7 | Trooper(), 8 | Squad( 9 | Trooper(), 10 | Trooper(), 11 | ), 12 | Trooper() 13 | ) 14 | 15 | val l = listOf() 16 | 17 | l.iterator() 18 | 19 | // For loop range must have an iterator method 20 | for (trooper in platoon) { 21 | println(trooper) 22 | } 23 | } 24 | 25 | 26 | class TrooperIterator(private val units: List) : Iterator { 27 | private var i = 0 28 | private var iterator: Iterator = this 29 | override fun hasNext(): Boolean { 30 | if (i >= units.size) { 31 | return false 32 | } 33 | if (i == units.size - 1) { 34 | if (iterator != this) { 35 | return iterator.hasNext() 36 | } 37 | } 38 | return true 39 | } 40 | 41 | override fun next(): Trooper { 42 | if (iterator != this) { 43 | if (iterator.hasNext()) { 44 | return iterator.next() 45 | } else { 46 | i++ 47 | iterator = this 48 | } 49 | } 50 | 51 | return when (val e = units[i]) { 52 | is Squad -> { 53 | iterator = e.iterator() 54 | this.next() 55 | } 56 | else -> { 57 | i++ 58 | e 59 | } 60 | } 61 | } 62 | } 63 | 64 | class Squad(private val units: List) : Trooper() { 65 | 66 | constructor(vararg units: Trooper) : this(units.toList()) 67 | 68 | operator fun iterator(): Iterator { 69 | return TrooperIterator(units) 70 | } 71 | } -------------------------------------------------------------------------------- /Chapter04/src/main/kotlin/7_Mediator.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val productManager = Michael 3 | val company = MyCompany(productManager) 4 | company.taskCompleted(true) 5 | } 6 | 7 | interface ProductManager { 8 | fun isAllGood(majorRelease: Boolean): Boolean 9 | } 10 | 11 | object Michael : Canary, ProductManager { 12 | private val kenny = Kenny(this) 13 | private val brad = Brad(this) 14 | 15 | override fun isAllGood(majorRelease: Boolean): Boolean { 16 | if (!kenny.isEating() && !kenny.isSleeping()) { 17 | println(kenny.doesMyCodeWork()) 18 | } else if (!brad.isEating() && !brad.isSleeping()) { 19 | println(brad.doesMyCodeWork()) 20 | } 21 | return true 22 | } 23 | } 24 | 25 | interface Canary { 26 | 27 | } 28 | 29 | interface QA { 30 | fun doesMyCodeWork(): Boolean 31 | } 32 | 33 | interface Parrot { 34 | fun isEating(): Boolean 35 | fun isSleeping(): Boolean 36 | } 37 | 38 | 39 | class Kenny(private val productManager: ProductManager) : QA, Parrot { 40 | override fun isSleeping(): Boolean { 41 | return false 42 | } 43 | 44 | override fun isEating(): Boolean { 45 | return false 46 | } 47 | 48 | override fun doesMyCodeWork(): Boolean { 49 | return true 50 | } 51 | } 52 | 53 | class Brad(private val productManager: ProductManager) : QA, Parrot { 54 | override fun isSleeping(): Boolean { 55 | return false 56 | } 57 | 58 | override fun isEating(): Boolean { 59 | return false 60 | } 61 | 62 | override fun doesMyCodeWork(): Boolean { 63 | return true 64 | } 65 | } 66 | 67 | object Me 68 | class MyCompany(private val productManager: ProductManager) { 69 | fun taskCompleted(isMajorRelease: Boolean) { 70 | println(productManager.isAllGood(isMajorRelease)) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Chapter04/src/main/kotlin/5_ChainOfResponsibility.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val req = Request( 3 | "developer@company.com", 4 | "Why do we need Software Architects?" 5 | ) 6 | 7 | val chain = basicValidation(authentication(finalResponse())) 8 | 9 | val res = chain(req) 10 | 11 | println(res) 12 | } 13 | 14 | data class Request(val email: String, val question: String) { 15 | fun isKnownEmail(): Boolean { 16 | return true 17 | } 18 | 19 | fun isFromJuniorDeveloper(): Boolean { 20 | return false 21 | } 22 | } 23 | 24 | // This is the incorrect implementation of what we want to achieve 25 | fun handleRequest(r: Request) { 26 | // Validate 27 | if (r.email.isEmpty() || r.question.isEmpty()) { 28 | return 29 | } 30 | 31 | // Authenticate 32 | // Make sure that you know whos is this user 33 | if (r.isKnownEmail()) { 34 | return 35 | } 36 | 37 | // Authorize 38 | // Requests from juniors are automatically ignored by architects 39 | if (r.isFromJuniorDeveloper()) { 40 | return 41 | } 42 | 43 | println("I don't know. Did you check StackOverflow?") 44 | } 45 | 46 | val authentication = fun(next: Handler) = 47 | fun(request: Request): Response { 48 | if (!request.isKnownEmail()) { 49 | throw IllegalArgumentException() 50 | } 51 | return next(request) 52 | } 53 | 54 | val basicValidation = fun(next: Handler) = 55 | fun(request: Request): Response { 56 | if (request.email.isEmpty() || request.question.isEmpty()) { 57 | throw IllegalArgumentException() 58 | } 59 | return next(request) 60 | } 61 | 62 | val finalResponse = fun() = 63 | fun(request: Request): Response { 64 | return Response("I don't know") 65 | } 66 | 67 | data class Response(val answer: String) 68 | 69 | typealias Handler = (request: Request) -> Response -------------------------------------------------------------------------------- /Chapter03/src/main/kotlin/5_Facade.kt: -------------------------------------------------------------------------------- 1 | import java.io.FileNotFoundException 2 | import kotlin.io.path.ExperimentalPathApi 3 | import kotlin.io.path.Path 4 | 5 | @OptIn(ExperimentalPathApi::class) 6 | fun main() { 7 | try { 8 | val server = Server.withPort(0).startFromConfiguration("/path/to/config") 9 | } catch (e: FileNotFoundException) { 10 | println("If there was a file and a parser, it would have worked") 11 | } 12 | } 13 | 14 | @ExperimentalPathApi 15 | fun Server.startFromConfiguration(fileLocation: String) { 16 | val path = Path(fileLocation) 17 | 18 | val lines = path.toFile().readLines() 19 | 20 | val configuration = try { 21 | JsonParser().server(lines) 22 | } catch (e: RuntimeException) { 23 | YamlParser().server(lines) 24 | } 25 | 26 | Server.withPort(configuration.port) 27 | } 28 | 29 | class Server private constructor(port: Int) { 30 | companion object { 31 | fun withPort(port: Int): Server { 32 | return Server(port) 33 | } 34 | } 35 | } 36 | 37 | interface Parser { 38 | fun property(prop: String): Property 39 | fun server(propertyStrings: List): ServerConfiguration 40 | } 41 | 42 | class YamlParser : Parser { 43 | // Implementation specific to YAML files 44 | override fun property(prop: String): Property { 45 | TODO("Not yet implemented") 46 | } 47 | 48 | override fun server(propertyStrings: List): ServerConfiguration { 49 | TODO("Not yet implemented") 50 | } 51 | } 52 | 53 | class JsonParser : Parser { 54 | 55 | // Implementation specific to JSON files 56 | override fun property(prop: String): Property { 57 | TODO("Not yet implemented") 58 | } 59 | 60 | override fun server(propertyStrings: List): ServerConfiguration { 61 | TODO("Not yet implemented") 62 | } 63 | } 64 | 65 | class Property 66 | 67 | class ServerConfiguration { 68 | var port: Int = 8080 69 | } -------------------------------------------------------------------------------- /Chapter08/src/main/kotlin/4_Pipeline.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.CoroutineScope 2 | import kotlinx.coroutines.channels.ReceiveChannel 3 | import kotlinx.coroutines.channels.consumeEach 4 | import kotlinx.coroutines.channels.produce 5 | import kotlinx.coroutines.delay 6 | import kotlinx.coroutines.isActive 7 | import kotlinx.coroutines.runBlocking 8 | import java.util.concurrent.TimeUnit 9 | 10 | fun main() { 11 | runBlocking { 12 | val pagesProducer = producePages() 13 | val domProducer = produceDom(pagesProducer) 14 | val titleProducer = produceTitles(domProducer) 15 | titleProducer.consumeEach { 16 | println(it) 17 | } 18 | } 19 | } 20 | 21 | fun CoroutineScope.producePages() = produce { 22 | // This should actually fetch something from the Internet 23 | fun getPages(): List { 24 | return listOf( 25 | "

Cool stuff

", 26 | "

Even more stuff

" 27 | ) 28 | } 29 | 30 | val pages = getPages() 31 | 32 | while (this.isActive) { 33 | for (p in pages) { 34 | send(p) 35 | } 36 | delay(TimeUnit.SECONDS.toMillis(5)) 37 | } 38 | } 39 | 40 | fun CoroutineScope.produceDom(pages: ReceiveChannel) = produce { 41 | fun parseDom(page: String): Document { 42 | // In reality this would use a DOM library to parse string to DOM 43 | return Document(page) 44 | } 45 | 46 | for (p in pages) { 47 | send(parseDom(p)) 48 | } 49 | } 50 | 51 | fun CoroutineScope.produceTitles(parsedPages: ReceiveChannel) = produce { 52 | fun getTitles(dom: Document): List { 53 | return dom.getElementsByTagName("h1").map { 54 | it.toString() 55 | } 56 | } 57 | 58 | for (page in parsedPages) { 59 | for (t in getTitles(page)) { 60 | send(t) 61 | } 62 | } 63 | } 64 | 65 | data class Document(val html: String) { 66 | fun getElementsByTagName(tag: String): List { 67 | return listOf(Document("Some title")) 68 | } 69 | } -------------------------------------------------------------------------------- /Chapter11/src/main/kotlin/server.kt: -------------------------------------------------------------------------------- 1 | import io.vertx.core.Vertx 2 | import io.vertx.core.json.JsonObject 3 | import io.vertx.ext.web.Router 4 | import io.vertx.ext.web.handler.BodyHandler 5 | import io.vertx.kotlin.core.json.json 6 | import io.vertx.kotlin.core.json.obj 7 | import io.vertx.kotlin.coroutines.CoroutineVerticle 8 | import kotlinx.coroutines.launch 9 | 10 | fun main() { 11 | val vertx = Vertx.vertx() 12 | vertx.deployVerticle(ServerVerticle()) 13 | vertx.deployVerticle(CatsVerticle()) 14 | } 15 | 16 | class ServerVerticle : CoroutineVerticle() { 17 | override suspend fun start() { 18 | val router = router() 19 | 20 | vertx.createHttpServer() 21 | .requestHandler(router) 22 | .listen(8081) 23 | println("open http://localhost:8081/status") 24 | } 25 | 26 | private fun router(): Router { 27 | // Our router code comes here now 28 | 29 | val router = Router.router(vertx) 30 | router.route().handler(BodyHandler.create()) 31 | router.get("/status").handler { ctx -> 32 | val json = json { 33 | obj( 34 | "status" to "OK" 35 | ) 36 | } 37 | 38 | ctx.response() 39 | .setStatusCode(200) 40 | .end(json.toString()) 41 | } 42 | router.mountSubRouter("/cats", catsRouter()) 43 | 44 | return router 45 | } 46 | 47 | private fun catsRouter(): Router { 48 | val router = Router.router(vertx) 49 | router.delete("/:id").handler { ctx -> 50 | val id = ctx.request().getParam("id").toInt() 51 | vertx.eventBus().request("cats:delete", id) { 52 | ctx.end() 53 | } 54 | } 55 | router.put("/:id").handler { ctx -> 56 | launch { 57 | val id = ctx.request().getParam("id").toInt() 58 | val body: JsonObject = ctx.bodyAsJson.mergeIn(json { 59 | obj("id" to id) 60 | }) 61 | 62 | vertx.eventBus().request("cats:update", body) { res -> 63 | ctx.end(res.result().body().toString()) 64 | } 65 | } 66 | } 67 | return router 68 | } 69 | } 70 | 71 | 72 | -------------------------------------------------------------------------------- /Chapter03/src/main/kotlin/1_Decorator.kt: -------------------------------------------------------------------------------- 1 | import java.lang.IllegalStateException 2 | 3 | fun main() { 4 | val starTrekRepository = DefaultStarTrekRepository() 5 | val withValidating = ValidatingAdd(starTrekRepository) 6 | val withLoggingAndValidating = LoggingGetCaptain(withValidating) 7 | 8 | withLoggingAndValidating["USS Enterprise"] 9 | 10 | try { 11 | // Throws an exception: Kathryn Janeway name is longer than 15 characters! 12 | withLoggingAndValidating["USS Voyager"] = "Kathryn Janeway" 13 | } catch (e: IllegalStateException) { 14 | println(e) 15 | } 16 | 17 | println(withLoggingAndValidating is LoggingGetCaptain) // This is our top level decorator, no problem here 18 | println(withLoggingAndValidating is StarTrekRepository) // This is the interface we implement, still no problem 19 | //println(withLoggingAndValidating is ValidatingAdd) // We wrap this class, but compiler cannot validate it 20 | //println(withLoggingAndValidating is DefaultStarTrekRepository) // We wrap this class, but compiler cannot validate it 21 | } 22 | 23 | interface StarTrekRepository { 24 | operator fun get(starshipName: String): String 25 | operator fun set(starshipName: String, captainName: String) 26 | } 27 | 28 | class DefaultStarTrekRepository : StarTrekRepository { 29 | private val starshipCaptains = mutableMapOf("USS Enterprise" to "Jean-Luc Picard") 30 | 31 | override fun get(starshipName: String): String { 32 | return starshipCaptains[starshipName] ?: "Unknown" 33 | } 34 | 35 | override fun set(starshipName: String, captainName: String) { 36 | starshipCaptains[starshipName] = captainName 37 | } 38 | } 39 | 40 | class LoggingGetCaptain(private val repository: StarTrekRepository) : StarTrekRepository by repository { 41 | override fun get(starshipName: String): String { 42 | println("Getting captain for $starshipName") 43 | return repository[starshipName] 44 | } 45 | } 46 | 47 | class ValidatingAdd(private val repository: StarTrekRepository) : StarTrekRepository by repository { 48 | private val maxNameLength = 15 49 | override fun set(starshipName: String, captainName: String) { 50 | require(captainName.length < maxNameLength) { 51 | "$captainName name is longer than $maxNameLength characters!" 52 | } 53 | 54 | repository[starshipName] = captainName 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /Chapter04/src/main/kotlin/9_Visitor.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | 3 | val page = Page( 4 | Container( 5 | Image, 6 | Link, 7 | Image 8 | ), 9 | Table, 10 | Link, 11 | Container( 12 | Table, 13 | Link 14 | ), 15 | Container( 16 | Image, 17 | Container( 18 | Image, 19 | Link 20 | ) 21 | ) 22 | ) 23 | 24 | println(collectLinks(page)) 25 | } 26 | 27 | fun collectLinks(page: Page): List { 28 | // No need for intermediate variable there 29 | return LinksCrawler().run { 30 | page.accept(this) 31 | this.links 32 | } 33 | } 34 | 35 | 36 | class LinksCrawler { 37 | private var _links = mutableListOf() 38 | 39 | val links 40 | get() = _links.toList() 41 | 42 | fun visit(page: Page) { 43 | visit(page.elements) 44 | } 45 | 46 | fun visit(container: Container) = visit(container.elements) 47 | 48 | private fun visit(elements: List) { 49 | for (e in elements) { 50 | when (e) { 51 | is Container -> e.accept(this) 52 | is Link -> _links.add(e.href) 53 | is Image -> _links.add(e.src) 54 | else -> { 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | private fun Container.accept(feature: LinksCrawler) { 62 | feature.visit(this) 63 | } 64 | 65 | // Same as above but shorter 66 | private fun Page.accept(feature: LinksCrawler) = feature.visit(this) 67 | 68 | 69 | class Page(val elements: MutableList = mutableListOf()) { 70 | constructor(vararg elements: HtmlElement) : this(mutableListOf()) { 71 | for (s in elements) { 72 | this.elements.add(s) 73 | } 74 | } 75 | } 76 | 77 | 78 | sealed class HtmlElement 79 | 80 | class Container(val elements: MutableList = mutableListOf()) : HtmlElement() { 81 | 82 | constructor(vararg units: HtmlElement) : this(mutableListOf()) { 83 | for (u in units) { 84 | this.elements.add(u) 85 | } 86 | } 87 | } 88 | 89 | object Image : HtmlElement() { 90 | val src: String 91 | get() = "https://some.image" 92 | } 93 | 94 | object Link : HtmlElement() { 95 | val href: String 96 | get() = "https://some.link" 97 | } 98 | 99 | object Table : HtmlElement() -------------------------------------------------------------------------------- /Chapter03/src/main/kotlin/2_Adapter.kt: -------------------------------------------------------------------------------- 1 | import java.util.stream.Stream 2 | import kotlin.streams.toList 3 | 4 | fun main() { 5 | // This code won't work 6 | /* 7 | cellPhone( 8 | // Type mismatch: inferred type is UsbMini but UsbTypeC was expected 9 | charger( 10 | // Type mismatch: inferred type is USPlug but EUPlug was expected 11 | usPowerOutlet() 12 | ) 13 | )*/ 14 | 15 | cellPhone( 16 | charger( 17 | usPowerOutlet().toEUPlug() 18 | ).toUsbTypeC() 19 | ) 20 | 21 | 22 | val l = listOf("a", "b", "c") 23 | 24 | streamProcessing(l.stream()) 25 | 26 | val s = (Stream.generate { 42 }).toList() 27 | println(s) 28 | 29 | // Using an adapter in a wrong way may cause your program to never stop! 30 | // For example: 31 | /* 32 | println("Collecting elements") 33 | collectionProcessing(s.toList()) 34 | */ 35 | } 36 | 37 | fun collectionProcessing(c: Collection) { 38 | for (e in c) { 39 | println(e) 40 | } 41 | } 42 | 43 | fun streamProcessing(stream: Stream) { 44 | // Do something with stream 45 | } 46 | 47 | fun USPlug.toEUPlug(): EUPlug { 48 | val hasPower = if (this.hasPower == 1) "TRUE" else "FALSE" 49 | return object : EUPlug { 50 | // Transfer power 51 | override val hasPower = hasPower 52 | } 53 | } 54 | 55 | fun UsbMini.toUsbTypeC(): UsbTypeC { 56 | val hasPower = this.hasPower == Power.TRUE 57 | return object : UsbTypeC { 58 | override val hasPower = hasPower 59 | } 60 | } 61 | 62 | // Power outlet exposes USPlug interface 63 | fun usPowerOutlet(): USPlug { 64 | return object : USPlug { 65 | override val hasPower = 1 66 | } 67 | } 68 | 69 | // Charger accepts EUPlug interface and exposes UsbMini interface 70 | fun charger(plug: EUPlug): UsbMini { 71 | return object : UsbMini { 72 | override val hasPower = Power.valueOf(plug.hasPower) 73 | } 74 | } 75 | 76 | fun cellPhone(chargeCable: UsbTypeC) { 77 | if (chargeCable.hasPower) { 78 | println("I've Got The Power!") 79 | } else { 80 | println("No power") 81 | } 82 | } 83 | 84 | interface USPlug { 85 | val hasPower: Int 86 | } 87 | 88 | interface EUPlug { 89 | val hasPower: String // "TRUE" or "FALSE" 90 | } 91 | 92 | 93 | interface UsbMini { 94 | val hasPower: Power 95 | } 96 | 97 | enum class Power { 98 | TRUE, FALSE 99 | } 100 | 101 | interface UsbTypeC { 102 | val hasPower: Boolean 103 | } 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /Chapter08/src/main/kotlin/2_Barrier.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | import kotlin.random.Random 3 | import kotlin.system.measureTimeMillis 4 | 5 | fun main() { 6 | runBlocking { 7 | println(measureTimeMillis { 8 | fetchFavoriteCharacterWrong("Inigo Montoya") 9 | }) 10 | println(measureTimeMillis { 11 | fetchFavoriteCharacterCorrect("Inigo Montoya") 12 | }) 13 | val (name, catchphrase, _) = fetchFavoriteCharacterCorrect("Inigo Montoya") 14 | println("$name says: $catchphrase") 15 | val characters: List> = 16 | listOf( 17 | Me.getFavoriteCharacter(), 18 | Taylor.getFavoriteCharacter(), 19 | Michael.getFavoriteCharacter() 20 | ) 21 | 22 | println(characters.awaitAll()) 23 | } 24 | } 25 | 26 | suspend fun fetchFavoriteCharacterWrong(name: String) = coroutineScope { 27 | val catchphrase = getCatchphraseAsync(name).await() 28 | val picture = getPicture(name).await() 29 | 30 | FavoriteCharacter(name, catchphrase, picture) 31 | } 32 | 33 | suspend fun fetchFavoriteCharacterCorrect( 34 | name: String 35 | ) = coroutineScope { 36 | val catchphrase = getCatchphraseAsync(name) 37 | val picture = getPicture(name) 38 | 39 | FavoriteCharacter(name, catchphrase.await(), picture.await()) 40 | } 41 | 42 | data class FavoriteCharacter( 43 | val name: String, 44 | val catchphrase: String, 45 | val picture: ByteArray = Random.nextBytes(42) 46 | ) 47 | 48 | fun CoroutineScope.getCatchphraseAsync( 49 | characterName: String 50 | ) = async { 51 | // Simulate network call 52 | delay(100) 53 | when (characterName) { 54 | "Inigo Montoya" -> "Hello. My name is Inigo Montoya. You killed my father. Prepare to die." 55 | else -> "No catchprase found" 56 | } 57 | } 58 | 59 | fun CoroutineScope.getPicture( 60 | characterName: String 61 | ) = async { 62 | // Simulate network call 63 | delay(500) 64 | when (characterName) { 65 | else -> Random.nextBytes(42) 66 | } 67 | } 68 | 69 | object Michael { 70 | suspend fun getFavoriteCharacter() = coroutineScope { 71 | async { 72 | FavoriteCharacter("Terminator", "Hasta la vista, baby") 73 | } 74 | } 75 | } 76 | 77 | object Taylor { 78 | suspend fun getFavoriteCharacter() = coroutineScope { 79 | async { 80 | FavoriteCharacter("Don Vito Corleone", "I'm going to make him an offer he can't refuse") 81 | } 82 | } 83 | } 84 | 85 | object Me { 86 | suspend fun getFavoriteCharacter() = coroutineScope { 87 | async { 88 | // I already prepared the answer! 89 | FavoriteCharacter("Inigo Montoya", "Hello, my name is...") 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /Chapter01/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /Chapter02/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /Chapter03/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /Chapter04/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /Chapter05/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /Chapter06/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /Chapter07/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /Chapter08/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /Chapter09/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /Chapter10/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /Chapter11/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /Chapter10/src/test/kotlin/ServerTest.kt: -------------------------------------------------------------------------------- 1 | import io.ktor.application.* 2 | import io.ktor.http.* 3 | import io.ktor.server.testing.* 4 | import org.jetbrains.exposed.dao.EntityID 5 | import org.jetbrains.exposed.sql.SchemaUtils 6 | import org.jetbrains.exposed.sql.deleteAll 7 | import org.jetbrains.exposed.sql.insert 8 | import org.jetbrains.exposed.sql.insertAndGetId 9 | import org.jetbrains.exposed.sql.transactions.transaction 10 | import org.junit.jupiter.api.* 11 | import org.junit.jupiter.api.Assertions.assertEquals 12 | 13 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 14 | class ServerTest { 15 | @AfterAll 16 | fun cleanup() { 17 | DB.connect() 18 | transaction { 19 | SchemaUtils.drop(CatsTable) 20 | } 21 | } 22 | 23 | @BeforeAll 24 | fun setup() { 25 | DB.connect() 26 | transaction { 27 | SchemaUtils.create(CatsTable) 28 | } 29 | } 30 | 31 | @Test 32 | fun testStatus() { 33 | withTestApplication(Application::mainModule) { 34 | val response = handleRequest(HttpMethod.Get, "/status").response 35 | assertEquals(HttpStatusCode.OK, response.status()) 36 | assertEquals("""{"status":"OK"}""", response.content) 37 | } 38 | } 39 | 40 | @Test 41 | fun `POST creates a new cat`() { 42 | withTestApplication(Application::mainModule) { 43 | val response = handleRequest(HttpMethod.Post, "/cats") { 44 | addHeader( 45 | HttpHeaders.ContentType, 46 | ContentType.Application.FormUrlEncoded.toString() 47 | ) 48 | setBody( 49 | listOf( 50 | "name" to "Meatloaf", 51 | "age" to 4.toString() 52 | ).formUrlEncode() 53 | ) 54 | }.response 55 | assertEquals(HttpStatusCode.Created, response.status()) 56 | } 57 | } 58 | 59 | @Nested 60 | inner class `With cat in DB` { 61 | 62 | @Test 63 | fun `GET with ID fetches a single cat`() { 64 | withTestApplication(Application::mainModule) { 65 | val response = handleRequest(HttpMethod.Get, "/cats/$id").response 66 | assertEquals("""{"id":$id,"name":"Fluffy","age":0}""", response.content) 67 | } 68 | } 69 | 70 | lateinit var id: EntityID 71 | 72 | @BeforeEach 73 | fun setup() { 74 | DB.connect() 75 | id = transaction { 76 | CatsTable.insertAndGetId { cat -> 77 | cat[name] = "Fluffy" 78 | } 79 | } 80 | } 81 | 82 | @AfterEach 83 | fun teardown() { 84 | DB.connect() 85 | transaction { 86 | CatsTable.deleteAll() 87 | } 88 | } 89 | 90 | 91 | @Test 92 | fun `GET without ID fetches all cats`() { 93 | withTestApplication(Application::mainModule) { 94 | val response = handleRequest(HttpMethod.Get, "/cats").response 95 | assertEquals("""[{"id":$id,"name":"Fluffy","age":0}]""", response.content) 96 | } 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /Chapter11/src/test/kotlin/ServerTest.kt: -------------------------------------------------------------------------------- 1 | import io.vertx.core.Vertx 2 | import io.vertx.core.buffer.Buffer 3 | import io.vertx.ext.web.client.WebClient 4 | import io.vertx.ext.web.client.WebClientOptions 5 | import io.vertx.kotlin.core.json.json 6 | import io.vertx.kotlin.core.json.obj 7 | import io.vertx.kotlin.coroutines.await 8 | import io.vertx.sqlclient.Row 9 | import io.vertx.sqlclient.SqlClient 10 | import io.vertx.sqlclient.Tuple 11 | import kotlinx.coroutines.runBlocking 12 | import org.junit.jupiter.api.* 13 | import org.junit.jupiter.api.Assertions.assertEquals 14 | import org.junit.jupiter.api.Assertions.assertTrue 15 | 16 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 17 | class ServerTest { 18 | 19 | private val vertx: Vertx = Vertx.vertx() 20 | lateinit var client: WebClient 21 | lateinit var db: SqlClient 22 | 23 | @BeforeAll 24 | fun setup() { 25 | runBlocking { 26 | vertx.deployVerticle(ServerVerticle()).await() 27 | vertx.deployVerticle(CatsVerticle()).await() 28 | client = WebClient.create( 29 | vertx, 30 | WebClientOptions() 31 | .setDefaultPort(8081) 32 | .setDefaultHost("localhost") 33 | ) 34 | db = Db.connect(vertx) 35 | } 36 | } 37 | 38 | @AfterAll 39 | fun tearDown() { 40 | // And you want to stop your server once 41 | vertx.close() 42 | } 43 | 44 | @Test 45 | fun `status should return 200`() { 46 | runBlocking { 47 | val response = client.get("/status").send().await() 48 | 49 | assertEquals(200, response.statusCode()) 50 | } 51 | } 52 | 53 | @Nested 54 | inner class `With Cat` { 55 | lateinit var catRow: Row 56 | 57 | @BeforeEach 58 | fun createCats() { 59 | runBlocking { 60 | val result = db.preparedQuery( 61 | """INSERT INTO cats (name, age) 62 | VALUES ($1, $2) 63 | RETURNING ID""".trimIndent() 64 | ).execute(Tuple.of("Binky", 7)).await() 65 | catRow = result.first() 66 | } 67 | } 68 | 69 | @AfterEach 70 | fun deleteAll() { 71 | runBlocking { 72 | db.preparedQuery("DELETE FROM cats") 73 | .execute().await() 74 | } 75 | } 76 | 77 | @Test 78 | fun `delete deletes a cat by ID`() { 79 | runBlocking { 80 | val catId = catRow.getInteger(0) 81 | client.delete("/cats/${catId}").send().await() 82 | 83 | val result = db.preparedQuery("SELECT * FROM cats WHERE id = $1") 84 | .execute(Tuple.of(catId)).await() 85 | 86 | assertEquals(0, result.size()) 87 | } 88 | } 89 | 90 | @Test 91 | fun `put updates a cat by ID`() { 92 | runBlocking { 93 | val catId = catRow.getInteger(0) 94 | val requestBody = json { 95 | obj("name" to "Meatloaf", "age" to 4) 96 | } 97 | client.put("/cats/${catId}") 98 | .sendBuffer(Buffer.buffer(requestBody.toString())) 99 | .await() 100 | 101 | val result = db.preparedQuery("SELECT * FROM cats WHERE id = $1") 102 | .execute(Tuple.of(catId)).await() 103 | 104 | assertEquals("Meatloaf", result.first().getString("name")) 105 | assertEquals(4, result.first().getInteger("age")) 106 | } 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /Chapter06/src/main/kotlin/4_Threads_vs_Coroutines.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | import kotlin.system.measureTimeMillis 3 | import kotlin.time.ExperimentalTime 4 | import kotlin.time.measureTime 5 | 6 | fun main() { 7 | runBlocking { 8 | val t1 = measureTimeMillis { 9 | Blocking.profile("123") 10 | } 11 | 12 | val t2 = measureTimeMillis { 13 | Async().profile("123") 14 | } 15 | 16 | val t3 = measureTimeMillis { 17 | Suspend().profile("123") 18 | } 19 | 20 | println("Blocking code: $t1") 21 | println("Async: $t2") 22 | println("Suspend: $t3") 23 | } 24 | } 25 | 26 | class Blocking { 27 | companion object { 28 | fun profile(id: String): Profile { 29 | val bio = fetchBioOverHttp(id) // takes 1s 30 | val picture = fetchPictureFromDB(id) // takes 100ms 31 | val friends = fetchFriendsFromDB(id) // takes 500ms 32 | return Profile(bio, picture, friends) 33 | } 34 | 35 | private fun fetchFriendsFromDB(id: String): List { 36 | Thread.sleep(500) 37 | return emptyList() 38 | } 39 | 40 | private fun fetchPictureFromDB(id: String): ByteArray? { 41 | Thread.sleep(100) 42 | return null 43 | } 44 | 45 | private fun fetchBioOverHttp(id: String): String { 46 | Thread.sleep(1000) 47 | return "Alexey Soshin, Software Architect" 48 | } 49 | } 50 | } 51 | 52 | class Async { 53 | suspend fun profile(id: String): Profile { 54 | val bio = fetchBioOverHttpAsync(id) // takes 1s 55 | val picture = fetchPictureFromDBAsync(id) // takes 100ms 56 | val friends = fetchFriendsFromDBAsync(id) // takes 500ms 57 | return Profile(bio.await(), picture.await(), friends.await()) 58 | } 59 | 60 | private fun fetchFriendsFromDBAsync(id: String) = GlobalScope.async { 61 | delay(500) 62 | emptyList() 63 | } 64 | 65 | private fun fetchPictureFromDBAsync(id: String) = 66 | GlobalScope.async { 67 | delay(100) 68 | null 69 | } 70 | 71 | private fun fetchBioOverHttpAsync(id: String) = GlobalScope.async { 72 | delay(1000) 73 | "Alexey Soshin, Software Architect" 74 | } 75 | } 76 | 77 | class Suspend { 78 | suspend fun profile(id: String): Profile { 79 | val bio = fetchBioOverHttp(id) // takes 1s 80 | val picture = fetchPictureFromDB(id) // takes 100ms 81 | val friends = fetchFriendsFromDB(id) // takes 500ms 82 | return Profile(bio, picture, friends) 83 | } 84 | 85 | private suspend fun fetchFriendsFromDB(id: String): List { 86 | delay(500) 87 | return emptyList() 88 | } 89 | 90 | private suspend fun fetchPictureFromDB(id: String): ByteArray? { 91 | delay(100) 92 | return null 93 | } 94 | 95 | private suspend fun fetchBioOverHttp(id: String): String { 96 | delay(1000) 97 | return "Alexey Soshin, Software Architect" 98 | } 99 | } 100 | 101 | 102 | data class Profile(val bio: String, val picture: ByteArray?, val friends: List) 103 | 104 | /* 105 | suspend fun profile(state: Int, id: String, context: ArrayList): Profile { 106 | when (state) { 107 | 0 -> { 108 | context += fetchBioOverHttp(id) // takes 1s 109 | profile(1, id, context) 110 | } 111 | 1 -> { 112 | context += fetchPictureFromDB(id) // takes 100ms 113 | profile(2, id, context) 114 | } 115 | 2 -> { 116 | context += fetchFriendsFromDB(id) // takes 500ms 117 | profile(3, id, context) 118 | } 119 | 3 -> { 120 | val (bio, picture, friends) = context 121 | return Profile(bio, picture, friends) 122 | } 123 | } 124 | }*/ 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Kotlin Design Patterns and Best Practices - Second Edition 5 | 6 | About the Author 7 | 8 | This is the code repository for [Kotlin Design Patterns and Best Practices - Second Edition](https://www.packtpub.com/product/kotlin-design-patterns-and-best-practices-second-edition/9781801815727?utm_source=github&utm_medium=repository&utm_campaign=9781801815727), published by Packt. 9 | 10 | **Build scalable applications using traditional, reactive, and concurrent design patterns in Kotlin** 11 | 12 | ## What is this book about? 13 | Design patterns are well-known solutions to common architectural problems as they allow you to solve many problems efficiently and create a shared vocabulary between developers. This book shows you how easy it can be to implement traditional design patterns in the modern multi-paradigm Kotlin programming language, and takes you through the new patterns and paradigms that have emerged. 14 | 15 | This book covers the following exciting features: 16 | - Implement all the classical design patterns using the Kotlin programming language. 17 | - Apply reactive and concurrent design patterns to make your application more scalable. 18 | - Discover best practices in Kotlin and explore its new features. 19 | - Understand the key principles of functional programming and learn how they apply to Kotlin. 20 | - Find out how to write idiomatic Kotlin code and learn which patterns to avoid. 21 | - Harness the power of Kotlin to design concurrent and reliable systems with ease. 22 | - Create an effective microservice with Kotlin and the Ktor framework. 23 | 24 | If you feel this book is for you, get your [copy](https://www.amazon.com/dp/1801815720) today! 25 | 26 | ## Instructions and Navigations 27 | All of the code is organized into folders. For example, Chapter02. 28 | 29 | The code will look like the following: 30 | ``` 31 | val chan = produce(capacity = 10) { 32 | (1..10).forEach { 33 | send(it) 34 | } 35 | } 36 | ``` 37 | 38 | **Following is what you need for this book:** 39 | This book is for developers looking to apply design patterns they've learned from other languages in Kotlin to build reliable, scalable, and maintainable applications. Prior programming knowledge is necessary to get started with this book. Experience in Java or design patterns is helpful, but not mandatory. 40 | 41 | With the following software and hardware list you can run all code files present in the book (Chapter 1-11). 42 | ### Software and Hardware List 43 | | Chapter | Software required | OS required | 44 | | -------- | ------------------------------------ | ----------------------------------- | 45 | | 1-11 | Kotlin, IntelliJ IDEA Community Edition, OpenJDK 11 or higher | Windows, Mac OS X, and Linux (Any) | 46 | 47 | 48 | We also provide a PDF file that has color images of the screenshots/diagrams used in this book. [Click here to download it](https://static.packt-cdn.com/downloads/9781801815727_ColorImages.pdf). 49 | 50 | ### Related products 51 | * How to Build Android Apps with Kotlin [[Packt]](https://www.packtpub.com/free-ebook/how-to-build-android-apps-with-kotlin/9781838984113?utm_source=github&utm_medium=repository&utm_campaign=9781838984113) [[Amazon]](https://www.amazon.com/dp/1838984119) 52 | 53 | * Mastering Kotlin [[Packt]](https://www.packtpub.com/product/mastering-kotlin/9781838555726?utm_source=github&utm_medium=repository&utm_campaign=9781838555726) [[Amazon]](https://www.amazon.com/dp/1838555722) 54 | 55 | 56 | ## Get to Know the Author 57 | **Alexey Soshin** 58 | is a software architect with 15 years of experience in the industry. He started exploring Kotlin when Kotlin was still in beta, and since then has been a big enthusiast of the language. He's a conference speaker, published writer, and the author of a video course titled Pragmatic System Design. 59 | 60 | ## Other books by the authors 61 | * [Hands-on Design Patterns with Kotlin](https://www.packtpub.com/product/hands-on-design-patterns-with-kotlin/9781788998017?utm_source=github&utm_medium=repository&utm_campaign=9781788998017) 62 | ### Download a free PDF 63 | 64 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
65 |

https://packt.link/free-ebook/9781801815727

-------------------------------------------------------------------------------- /Chapter01/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /Chapter02/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /Chapter03/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /Chapter04/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /Chapter05/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /Chapter06/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /Chapter07/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /Chapter08/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | --------------------------------------------------------------------------------