├── README.md ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── Dockerfile ├── src ├── main │ ├── sql │ │ ├── addData.sql │ │ └── createSchema.sql │ └── kotlin │ │ └── pt │ │ └── isel │ │ └── ls │ │ ├── AppDB.kt │ │ ├── utils │ │ └── Ints.kt │ │ └── http │ │ └── HTTPServer.kt └── test │ └── kotlin │ └── pt │ └── isel │ └── ls │ ├── ExampleTest.kt │ └── utils │ └── IntsTests.kt ├── .gitignore ├── static-content ├── sparouter │ ├── index.html │ ├── router.js │ ├── index.js │ └── handlers.js ├── index.html └── spasimple │ ├── index.html │ └── index.js ├── gradlew.bat └── gradlew /README.md: -------------------------------------------------------------------------------- 1 | # 2223-2-common 2 | Software Laboratory, 2022/2023, Spring semester 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isel-leic-ls/2223-2-common/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:17 2 | WORKDIR /usr/app 3 | COPY ./static-content ./static-content 4 | COPY ./build/libs ./libs 5 | CMD ["java", "-jar", "./libs/2223-2-common.jar"] 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/sql/addData.sql: -------------------------------------------------------------------------------- 1 | insert into courses(name) values ('LEIC'); 2 | insert into students(course, number, name) values (1, 12345, 'Alice'); 3 | insert into students(course, number, name) select cid as course, 12346 as number, 'Bob' as name from courses where name = 'LEIC' -------------------------------------------------------------------------------- /src/main/sql/createSchema.sql: -------------------------------------------------------------------------------- 1 | drop table if exists students; 2 | drop table if exists courses; 3 | 4 | create table courses ( 5 | cid serial primary key, 6 | name varchar(80) 7 | ); 8 | 9 | create table students ( 10 | number int primary key, 11 | name varchar(80), 12 | course int references courses(cid) 13 | ); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | /build/ 4 | 5 | # Ignore Gradle GUI config 6 | gradle-app.setting 7 | 8 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 9 | !gradle-wrapper.jar 10 | 11 | # Cache of project 12 | .gradletasknamecache 13 | 14 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 15 | # gradle/wrapper/gradle-wrapper.properties 16 | -------------------------------------------------------------------------------- /src/test/kotlin/pt/isel/ls/ExampleTest.kt: -------------------------------------------------------------------------------- 1 | package pt.isel.ls 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | 6 | class ExampleTest { 7 | @Test 8 | fun example() { 9 | // arrange | given 10 | val a = 1 11 | val b = 2 12 | 13 | // act | when 14 | val result = a + b 15 | 16 | // assert | then 17 | assertEquals(3, result) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /static-content/sparouter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Students 5 | 6 | 7 | 8 | 9 | 10 | Home 11 | Students 12 | 13 |
14 | 15 |

Chelas 2022

16 | 17 | -------------------------------------------------------------------------------- /static-content/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Samples 5 | 6 | 7 | 8 | 9 |

LS - Sample Single Page Applications (SPAs)

10 | 14 |

Chelas 2022

15 | 16 | -------------------------------------------------------------------------------- /src/main/kotlin/pt/isel/ls/AppDB.kt: -------------------------------------------------------------------------------- 1 | package pt.isel.ls 2 | 3 | import org.postgresql.ds.PGSimpleDataSource 4 | 5 | fun main() { 6 | val dataSource = PGSimpleDataSource() 7 | val jdbcDatabaseURL = System.getenv("JDBC_DATABASE_URL") 8 | dataSource.setURL(jdbcDatabaseURL) 9 | // dataSource.setURL("jdbc:postgresql://localhost/postgres?user=postgres&password=postgres") 10 | 11 | dataSource.getConnection().use { 12 | val stm = it.prepareStatement("select * from students") 13 | val rs = stm.executeQuery() 14 | while (rs.next()) { 15 | println(rs.getString("name")) 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /static-content/sparouter/router.js: -------------------------------------------------------------------------------- 1 | const routes = [] 2 | let notFoundRouteHandler = () => { throw "Route handler for unknown routes not defined" } 3 | 4 | function addRouteHandler(path, handler){ 5 | routes.push({path, handler}) 6 | } 7 | function addDefaultNotFoundRouteHandler(notFoundRH) { 8 | notFoundRouteHandler = notFoundRH 9 | } 10 | 11 | function getRouteHandler(path){ 12 | const route = routes.find(r => r.path == path) 13 | return route ? route.handler : notFoundRouteHandler 14 | } 15 | 16 | const router = { 17 | addRouteHandler, 18 | getRouteHandler, 19 | addDefaultNotFoundRouteHandler 20 | } 21 | 22 | export default router -------------------------------------------------------------------------------- /static-content/spasimple/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Students 5 | 6 | 7 | 8 | 9 | 10 | Home 11 | Students 12 | Student with Id 10 13 | 14 |
15 | 16 |

Chelas 2022

17 | 18 | -------------------------------------------------------------------------------- /static-content/sparouter/index.js: -------------------------------------------------------------------------------- 1 | import router from "./router.js"; 2 | import handlers from "./handlers.js"; 3 | 4 | window.addEventListener('load', loadHandler) 5 | window.addEventListener('hashchange', hashChangeHandler) 6 | 7 | function loadHandler(){ 8 | 9 | router.addRouteHandler("home", handlers.getHome) 10 | router.addRouteHandler("students", handlers.getStudents) 11 | router.addRouteHandler("students/create", handlers.createStudent) 12 | router.addRouteHandler("students/10", handlers.getStudent) 13 | router.addDefaultNotFoundRouteHandler(() => window.location.hash = "home") 14 | 15 | hashChangeHandler() 16 | } 17 | 18 | function hashChangeHandler(){ 19 | 20 | const mainContent = document.getElementById("mainContent") 21 | const path = window.location.hash.replace("#", "") 22 | 23 | const handler = router.getRouteHandler(path) 24 | handler(mainContent) 25 | } -------------------------------------------------------------------------------- /src/test/kotlin/pt/isel/ls/utils/IntsTests.kt: -------------------------------------------------------------------------------- 1 | package pt.isel.ls.utils 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | import kotlin.test.assertFailsWith 6 | import kotlin.test.assertTrue 7 | 8 | class IntsTests { 9 | @Test 10 | fun max_returns_greatest() { 11 | assertEquals(1, max(1, -2)) 12 | assertEquals(1, max(-2, 1)) 13 | assertEquals(-1, max(-1, -2)) 14 | assertEquals(-1, max(-2, -1)) 15 | } 16 | 17 | @Test 18 | fun indexOfBinary_throws_IllegalArgumentException_if_indexes_are_not_valid() { 19 | assertFailsWith { 20 | // Arrange 21 | val v = intArrayOf(1, 2, 3) 22 | 23 | // Act 24 | val ix: Int = indexOfBinary(v, 2, 1, 4) 25 | 26 | // Assert 27 | assertTrue(ix < 0) 28 | } 29 | } 30 | 31 | @Test 32 | fun indexOfBinary_right_bound_parameter_is_exclusive() { 33 | val v = intArrayOf(2, 2, 2) 34 | val ix: Int = indexOfBinary(v, 1, 1, 2) 35 | assertTrue(ix < 0) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/kotlin/pt/isel/ls/utils/Ints.kt: -------------------------------------------------------------------------------- 1 | package pt.isel.ls.utils 2 | 3 | /** 4 | * Returns the maximum integer between two integer operands. 5 | * @param a the first operand. 6 | * @param b the second operand. 7 | * @return the greatest of the two integer operands. 8 | */ 9 | fun max(a: Int, b: Int): Int { 10 | return if (a >= b) a else b 11 | } 12 | 13 | /** 14 | * Looks for an integer in an sub-array and returns its index, if found. 15 | * Otherwise, returns -1; 16 | * @param a the array containing the sub-array to search. 17 | * @param fromIndex the first index of the sub-array. 18 | * @param toIndex the index after the last index of the sub-array. 19 | * @param n the integer to find. 20 | * @return the index of an occurrence of {@code n}, if {@code n} exists in the sub-array; 21 | * -1 otherwise. 22 | */ 23 | fun indexOfBinary(a: IntArray, fromIndex: Int, toIndex: Int, n: Int): Int { 24 | require(fromIndex <= toIndex) { "from($fromIndex) > to($toIndex)" } 25 | var low = fromIndex 26 | var high = toIndex - 1 27 | var mid: Int 28 | while (low < high) { 29 | mid = high + low / 2 + 1 30 | if (n > a[mid]) { 31 | low = mid + 1 32 | } else if (n < a[mid]) { 33 | high = mid - 1 34 | } else { 35 | return mid 36 | } 37 | } 38 | return -1 39 | } 40 | -------------------------------------------------------------------------------- /static-content/spasimple/index.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('load', loadHandler) 2 | window.addEventListener('hashchange', hashChangeHandler) 3 | 4 | function loadHandler(){ 5 | hashChangeHandler() 6 | } 7 | 8 | function hashChangeHandler(){ 9 | 10 | const mainContent = document.getElementById("mainContent") 11 | 12 | switch(window.location.hash){ 13 | case '#home' : return home() 14 | case '#students' : return students() 15 | case '#students/10' : return studentDetails() 16 | default : return defaultRoute() 17 | } 18 | 19 | // Routes handler functions 20 | 21 | function home() { 22 | const h1 = document.createElement("h1") 23 | const text = document.createTextNode("Home"); 24 | h1.appendChild(text) 25 | mainContent.replaceChildren(h1) 26 | } 27 | 28 | function students() { 29 | fetch("http://localhost:9000/students") 30 | .then(res => res.json()) 31 | .then(students => { 32 | const text = document.createTextNode(JSON.stringify(students)); 33 | mainContent.replaceChildren(text) 34 | }) 35 | } 36 | 37 | function studentDetails() { 38 | fetch("http://localhost:9000/students/10") 39 | .then(res => res.json()) 40 | .then(student => { 41 | console.log(student) 42 | const text = document.createTextNode(JSON.stringify(student)); 43 | mainContent.replaceChildren(text) 44 | }) 45 | } 46 | 47 | function defaultRoute() { 48 | window.location.hash = "home" 49 | } 50 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/main/kotlin/pt/isel/ls/http/HTTPServer.kt: -------------------------------------------------------------------------------- 1 | package pt.isel.ls.http 2 | 3 | import kotlinx.datetime.Clock 4 | import kotlinx.serialization.Serializable 5 | import kotlinx.serialization.decodeFromString 6 | import kotlinx.serialization.encodeToString 7 | import kotlinx.serialization.json.Json 8 | import org.http4k.core.Method.GET 9 | import org.http4k.core.Method.POST 10 | import org.http4k.core.Request 11 | import org.http4k.core.Response 12 | import org.http4k.core.Status.Companion.CREATED 13 | import org.http4k.core.Status.Companion.OK 14 | import org.http4k.routing.ResourceLoader 15 | import org.http4k.routing.bind 16 | import org.http4k.routing.path 17 | import org.http4k.routing.routes 18 | import org.http4k.routing.singlePageApp 19 | import org.http4k.server.Jetty 20 | import org.http4k.server.asServer 21 | import org.postgresql.ds.PGSimpleDataSource 22 | import org.slf4j.LoggerFactory 23 | 24 | private val logger = LoggerFactory.getLogger("pt.isel.ls.http.HTTPServer") 25 | 26 | @Serializable 27 | data class Student(val name: String, val number: Int) 28 | 29 | val students = mutableListOf( 30 | Student("Filipe", 10), 31 | Student("Luis", 20), 32 | Student("Daniel", 30) 33 | ) 34 | 35 | fun getStudents(request: Request): Response { 36 | logRequest(request) 37 | val limit = request.query("limit")?.toInt() ?: 5 38 | return Response(OK) 39 | .header("content-type", "application/json") 40 | .body(Json.encodeToString(students.take(limit))) 41 | } 42 | 43 | fun getStudent(request: Request): Response { 44 | logRequest(request) 45 | val stdNumber = request.path("number")?.toInt() 46 | return Response(OK) 47 | .header("content-type", "application/json") 48 | .body(Json.encodeToString(students.find { it.number == stdNumber })) 49 | } 50 | 51 | fun postStudent(request: Request): Response { 52 | logRequest(request) 53 | val std = Json.decodeFromString(request.bodyString()) 54 | students.add(std) 55 | return Response(CREATED) 56 | .header("content-type", "application/json") 57 | .body(Json.encodeToString(std)) 58 | } 59 | 60 | fun getDate(request: Request): Response { 61 | return Response(OK) 62 | .header("content-type", "text/plain") 63 | .body(Clock.System.now().toString()) 64 | } 65 | 66 | fun getStudentsFromPostgres(request: Request): Response { 67 | logRequest(request) 68 | val dataSource = PGSimpleDataSource() 69 | val jdbcDatabaseURL = System.getenv("JDBC_DATABASE_URL") ?: "jdbc:postgresql://localhost/postgres?user=postgres&password=postgres" 70 | dataSource.setURL(jdbcDatabaseURL) 71 | 72 | val pStudents = mutableListOf() 73 | dataSource.connection.use { 74 | val stm = it.prepareStatement("select name,number from students") 75 | val rs = stm.executeQuery() 76 | while (rs.next()) { 77 | pStudents.add(Student(rs.getString("name"), rs.getInt("number"))) 78 | } 79 | } 80 | return Response(OK) 81 | .header("content-type", "application/json") 82 | .body(Json.encodeToString(pStudents)) 83 | } 84 | 85 | fun logRequest(request: Request) { 86 | logger.info( 87 | "incoming request: method={}, uri={}, content-type={} accept={}", 88 | request.method, 89 | request.uri, 90 | request.header("content-type"), 91 | request.header("accept") 92 | ) 93 | } 94 | 95 | fun main() { 96 | val studentRoutes = routes( 97 | "students" bind GET to ::getStudents, 98 | "students/{number}" bind GET to ::getStudent, 99 | "students" bind POST to ::postStudent 100 | ) 101 | 102 | val app = routes( 103 | studentRoutes, 104 | "date" bind GET to ::getDate, 105 | "postgres/students" bind GET to ::getStudentsFromPostgres, 106 | singlePageApp(ResourceLoader.Directory("static-content")) 107 | ) 108 | 109 | val port = System.getenv("PORT")?.toIntOrNull() ?: 9000 110 | val jettyServer = app.asServer(Jetty(port)).start() 111 | logger.info("server started listening") 112 | 113 | readln() 114 | jettyServer.stop() 115 | 116 | logger.info("leaving Main") 117 | } 118 | -------------------------------------------------------------------------------- /static-content/sparouter/handlers.js: -------------------------------------------------------------------------------- 1 | /* 2 | This example creates the students views using directly the DOM Api 3 | But you can create the views in a different way, for example, for the student details you can: 4 | createElement("ul", 5 | createElement("li", "Name : " + student.name), 6 | createElement("li", "Number : " + student.number) 7 | ) 8 | or 9 | ul( 10 | li("Name : " + student.name), 11 | li("Number : " + student.name) 12 | ) 13 | Note: You have to use the DOM Api, but not directly 14 | */ 15 | 16 | const API_BASE_URL = "https://ls-students.onrender.com/" 17 | 18 | function getHome(mainContent){ 19 | 20 | const h1 = document.createElement("h1") 21 | const text = document.createTextNode("Home") 22 | h1.appendChild(text) 23 | mainContent.replaceChildren(h1) 24 | } 25 | 26 | function getStudents(mainContent){ 27 | fetch(API_BASE_URL + "students") 28 | .then(res => res.json()) 29 | .then(students => { 30 | const div = document.createElement("div") 31 | 32 | const h1 = document.createElement("h1") 33 | const text = document.createTextNode("Students") 34 | h1.appendChild(text) 35 | div.appendChild(h1) 36 | 37 | const aCreateStudent = document.createElement("a") 38 | const createText = document.createTextNode("New Student" ); 39 | aCreateStudent.appendChild(createText) 40 | aCreateStudent.href="#students/create" 41 | div.appendChild(aCreateStudent) 42 | 43 | students.forEach(s => { 44 | const p = document.createElement("p") 45 | const a = document.createElement("a") 46 | const aText = document.createTextNode("Link Example to students/" + s.number); 47 | a.appendChild(aText) 48 | a.href="#students/" + s.number 49 | p.appendChild(a) 50 | div.appendChild(p) 51 | }) 52 | mainContent.replaceChildren(div) 53 | }) 54 | } 55 | 56 | function getStudent(mainContent){ 57 | fetch(API_BASE_URL + "students/10") 58 | .then(res => res.json()) 59 | .then(student => { 60 | const ulStd = document.createElement("ul") 61 | 62 | const liName = document.createElement("li") 63 | const textName = document.createTextNode("Name : " + student.name) 64 | liName.appendChild(textName) 65 | 66 | const liNumber = document.createElement("li") 67 | const textNumber = document.createTextNode("Number : " + student.number) 68 | liNumber.appendChild(textNumber) 69 | 70 | ulStd.appendChild(liName) 71 | ulStd.appendChild(liNumber) 72 | 73 | mainContent.replaceChildren(ulStd) 74 | }) 75 | } 76 | 77 | /*
78 | 79 | 80 | 81 | 82 | 83 |
*/ 84 | 85 | function createStudent(mainContent){ 86 | const form = document.createElement("form") 87 | 88 | const labelName = document.createElement("label") 89 | const textName = document.createTextNode("Name") 90 | labelName.appendChild(textName) 91 | const inputName = document.createElement("input") 92 | inputName.type = "text" 93 | inputName.id = "idName" 94 | 95 | const labelNumber = document.createElement("label") 96 | const textNumber = document.createTextNode("Number") 97 | labelNumber.appendChild(textNumber) 98 | const inputNumber= document.createElement("input") 99 | inputNumber.type = "text" 100 | inputNumber.id = "idNumber" 101 | 102 | const inputSubmit = document.createElement("input") 103 | inputSubmit.type = "submit" 104 | 105 | form.appendChild(labelName) 106 | form.appendChild(inputName) 107 | form.appendChild(labelNumber) 108 | form.appendChild(inputNumber) 109 | form.appendChild(inputSubmit) 110 | 111 | form.addEventListener('submit', handleSubmit) 112 | 113 | function handleSubmit(e) { 114 | e.preventDefault() 115 | const inputName = document.querySelector("#idName") 116 | const inputNumber = document.querySelector("#idNumber") 117 | const options = { 118 | method : "POST", 119 | headers : { 120 | "Content-Type" : "application/json", 121 | "Accept" : "application/json" 122 | }, 123 | body : JSON.stringify({ 124 | name : inputName.value, 125 | number : parseInt(inputNumber.value) 126 | }) 127 | } 128 | fetch(API_BASE_URL + "students", options) 129 | .then(res => res.json()) 130 | .then(student => { 131 | console.log(student) 132 | window.location.hash = "students" 133 | }) 134 | } 135 | mainContent.replaceChildren(form) 136 | } 137 | 138 | export const handlers = { 139 | getHome, 140 | getStudent, 141 | getStudents, 142 | createStudent 143 | } 144 | 145 | export default handlers -------------------------------------------------------------------------------- /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 | MSYS* | 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 | --------------------------------------------------------------------------------