├── Procfile ├── activator-launch-1.3.2.jar ├── project ├── build.properties └── plugins.sbt ├── src ├── main │ ├── resources │ │ └── application.conf │ └── scala │ │ ├── ReverseProxy.scala │ │ └── DemoApp.scala └── test │ └── scala │ ├── SampleServiceSpec.scala │ └── ProxyServiceSpec.scala ├── .gitignore ├── app.json ├── README.md ├── LICENSE └── activator /Procfile: -------------------------------------------------------------------------------- 1 | web: target/universal/stage/bin/akka-http-microservice -Dhttp.port=$PORT 2 | -------------------------------------------------------------------------------- /activator-launch-1.3.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fkowal/akka-http-reverse-proxy/HEAD/activator-launch-1.3.2.jar -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | #Activator-generated Properties 2 | #Thu Mar 31 22:47:21 CEST 2016 3 | template.uuid=7dd85950-cd89-4083-9606-c76dfa4ceec6 4 | sbt.version=0.13.11 5 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("io.spray" % "sbt-revolver" % "0.7.2") 2 | 3 | addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0") 4 | 5 | addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.0.1") 6 | -------------------------------------------------------------------------------- /src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | akka { 2 | loglevel = DEBUG 3 | } 4 | 5 | http { 6 | interface = "0.0.0.0" 7 | port = 9000 8 | } 9 | 10 | proxy { 11 | service1 = "http://localhost:9000" 12 | service2 = "http://localhost:9001" 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.log 3 | 4 | # sbt specific 5 | .cache 6 | .history 7 | .lib/ 8 | dist/* 9 | target/ 10 | lib_managed/ 11 | src_managed/ 12 | project/boot/ 13 | project/plugins/project/ 14 | 15 | # Scala-IDE specific 16 | .scala_dependencies 17 | .worksheet 18 | 19 | # IntelliJ specific 20 | .idea -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Akka HTTP microservice example", 3 | "description": "Simple (micro)service which demonstrates how to accomplish tasks typical for REST service using Akka HTTP.", 4 | "website": "https://typesafe.com/activator/template/akka-http-microservice", 5 | "success_url": "/ip/8.8.8.8" 6 | } 7 | -------------------------------------------------------------------------------- /src/test/scala/SampleServiceSpec.scala: -------------------------------------------------------------------------------- 1 | import akka.http.scaladsl.model.StatusCodes._ 2 | import akka.http.scaladsl.testkit.ScalatestRouteTest 3 | import org.scalatest._ 4 | 5 | class SampleServiceSpec extends FlatSpec with Matchers with ScalatestRouteTest with SampleService { 6 | override def testConfigSource = "akka.loglevel = WARNING" 7 | val repo = new PersonRepository 8 | 9 | "Service" should "respond to single IP query" in { 10 | Get("/") ~> appRoutes ~> check { 11 | status shouldBe OK 12 | responseAs[String] shouldBe "witam" 13 | } 14 | } 15 | 16 | it should "consume Person and Respond with Response" in { 17 | Post(s"/api/test", Person("john", 30)) ~> appRoutes ~> check { 18 | status shouldBe OK 19 | responseAs[Response] shouldBe Response(31) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Akka Http Reverse Proxy 2 | 3 | ## Usage 4 | 5 | Start ReverseProxy service running on port 9000 with sbt: 6 | 7 | ``` 8 | $ sbt 9 | > ~re-start 10 | ``` 11 | 12 | in second terminal run DemoApp on port 9001 13 | ``` 14 | sbt run 15 | ``` 16 | 17 | With the service up, you can start sending HTTP requests: 18 | 19 | Directly to DemoService 20 | ``` 21 | $ curl http://localhost:9001/api/person/maciej 22 | { 23 | "city": "maciej", 24 | "age": 123 25 | } 26 | ``` 27 | Or via Reverse Proxy 28 | ``` 29 | $ curl http://localhost:9000/service2/api/person/maciej 30 | ``` 31 | 32 | 33 | ### Testing 34 | 35 | Execute tests using `test` command: 36 | 37 | ``` 38 | $ sbt 39 | > test 40 | ``` 41 | 42 | ## Author & license 43 | 44 | Maciej Kowalski 45 | 46 | For licensing info see LICENSE file in project's root directory. 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /src/test/scala/ProxyServiceSpec.scala: -------------------------------------------------------------------------------- 1 | import java.net.URI 2 | 3 | import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport 4 | import akka.http.scaladsl.model.{HttpRequest, HttpResponse, StatusCodes} 5 | import akka.http.scaladsl.testkit.ScalatestRouteTest 6 | import akka.stream.scaladsl.Flow 7 | import org.scalatest.{FlatSpec, Matchers} 8 | import spray.json.DefaultJsonProtocol 9 | 10 | case class ProxyResponse(method: String, path: String, query: Option[String]) 11 | 12 | class ProxyServiceSpec extends FlatSpec with Matchers with ScalatestRouteTest with ProxyService with DefaultJsonProtocol with SprayJsonSupport { 13 | override val proxies: Map[String, URI] = Map("service" -> new URI("http://localhost:9000/mocked")) 14 | 15 | implicit val ProxyReponseFormat = jsonFormat3(ProxyResponse) 16 | 17 | override def flow(uri: URI): Flow[HttpRequest, HttpResponse, Any] = 18 | Flow[HttpRequest].map { 19 | request => HttpResponse(status = StatusCodes.OK, entity = marshal( 20 | ProxyResponse(request.method.value, path = request.uri.path.toString, query = request.uri.rawQueryString) 21 | )) 22 | } 23 | 24 | "ProxyService" should "respond to single IP query" in { 25 | Get("/service/part1/part2?q=1") ~> proxyRoutes ~> check { 26 | status shouldBe StatusCodes.OK 27 | responseAs[ProxyResponse] shouldBe ProxyResponse("GET", "/part1/part2", Some("q=1")) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/scala/ReverseProxy.scala: -------------------------------------------------------------------------------- 1 | import java.net.URI 2 | 3 | import akka.actor.ActorSystem 4 | import akka.http.scaladsl.Http 5 | import akka.http.scaladsl.model.{HttpRequest, HttpResponse, Uri} 6 | import akka.http.scaladsl.server.Directives._ 7 | import akka.http.scaladsl.server.{RequestContext, RouteResult} 8 | import akka.stream.ActorMaterializer 9 | import akka.stream.scaladsl.{Flow, Sink, Source} 10 | import com.typesafe.config.ConfigFactory 11 | 12 | import scala.concurrent.{ExecutionContextExecutor, Future} 13 | 14 | trait ProxyService { 15 | implicit val system: ActorSystem 16 | implicit def executor: ExecutionContextExecutor 17 | implicit val materializer: ActorMaterializer 18 | 19 | val proxies: Map[String, URI] 20 | 21 | def flow(uri: URI): Flow[HttpRequest, HttpResponse, Any] = 22 | Http(system).outgoingConnection(uri.getHost, uri.getPort) 23 | 24 | def proxyTo(context: RequestContext, flow: Flow[HttpRequest, HttpResponse, Any]): Future[RouteResult] = { 25 | val query = context.request.uri.rawQueryString.map("?"+_).getOrElse("") 26 | 27 | val requestUri = Uri(context.unmatchedPath.toString() + query) 28 | 29 | val proxyRequest = context.request.copy(uri = requestUri) 30 | 31 | Source.single(proxyRequest) 32 | .via(flow) 33 | .runWith(Sink.head) 34 | .flatMap(context.complete(_)) 35 | } 36 | 37 | def proxyRoutes(proxies: Map[String, URI]) = pathPrefix(Segment) { 38 | serviceName => 39 | proxies.get(serviceName) match { 40 | case Some(uri) => 41 | (context: RequestContext) => proxyTo(context, flow(uri)) 42 | case None => reject 43 | } 44 | } 45 | } 46 | 47 | object ReverseProxy extends App with ProxyService { 48 | override implicit val system = ActorSystem() 49 | override implicit val executor = system.dispatcher 50 | override implicit val materializer = ActorMaterializer() 51 | 52 | val config = ConfigFactory.load() 53 | import scala.collection.JavaConverters._ 54 | 55 | val proxies: Map[String, URI] = config.getConfig("proxy").entrySet().asScala 56 | .map(entry => entry.getKey -> new URI(entry.getValue.unwrapped().toString)).toMap 57 | 58 | 59 | val appRoutes = proxyRoutes(proxies) 60 | 61 | Http().bindAndHandle(appRoutes, config.getString("http.interface"), config.getInt("http.port")) 62 | } 63 | -------------------------------------------------------------------------------- /src/main/scala/DemoApp.scala: -------------------------------------------------------------------------------- 1 | import akka.actor.ActorSystem 2 | import akka.http.scaladsl.Http 3 | import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport 4 | import akka.http.scaladsl.server.Directives._ 5 | import akka.http.scaladsl.server.Route 6 | import akka.stream.ActorMaterializer 7 | import spray.json._ 8 | 9 | import scala.concurrent.{ExecutionContextExecutor, Future} 10 | 11 | case class Person(name: String, age: Int) 12 | 13 | trait JsonSupport extends DefaultJsonProtocol with SprayJsonSupport { 14 | implicit val personFormat = jsonFormat2(Person) 15 | } 16 | 17 | class PersonRepository { 18 | private val store = scala.collection.mutable.Map[String, Person]() 19 | 20 | def save(person: Person): Future[Option[Person]] = { 21 | if (person.name == "err") { 22 | Future.failed(new RuntimeException("bad name")) 23 | } else { 24 | Future.successful(store.put(person.name, person)) 25 | } 26 | } 27 | 28 | def find(id: String): Future[Option[Person]] = { 29 | if(id =="err") { 30 | Future.failed(new RuntimeException("somerror")) 31 | } else if (id =="maciej") { 32 | Future.successful(Some(Person("maciej", 12))) 33 | } else { 34 | Future.successful(store.get(id)) 35 | } 36 | } 37 | } 38 | 39 | trait SampleService extends JsonSupport { 40 | implicit def executor: ExecutionContextExecutor 41 | 42 | def appRoutes(repo: PersonRepository): Route = 43 | post { 44 | entity(as[Person]) { person => 45 | complete { 46 | repo.save(person) 47 | } 48 | } 49 | } ~ 50 | pathPrefix(Segment) { id => 51 | get { 52 | val futurePerson = repo.find(id) 53 | rejectEmptyResponse( 54 | complete(futurePerson) 55 | ) 56 | } 57 | } 58 | } 59 | 60 | object DemoApp extends App with SampleService { 61 | 62 | implicit val system = ActorSystem() 63 | implicit val executor: ExecutionContextExecutor = system.dispatcher 64 | implicit val materializer = ActorMaterializer() 65 | 66 | val repo = new PersonRepository 67 | 68 | val routes = path("") { 69 | complete("service2") 70 | } ~ pathPrefix("api" / "person") { 71 | appRoutes(repo) 72 | } 73 | 74 | Http().bindAndHandle(routes, "localhost", 9001) 75 | } 76 | -------------------------------------------------------------------------------- /activator: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ### ------------------------------- ### 4 | ### Helper methods for BASH scripts ### 5 | ### ------------------------------- ### 6 | 7 | realpath () { 8 | ( 9 | TARGET_FILE="$1" 10 | 11 | cd "$(dirname "$TARGET_FILE")" 12 | TARGET_FILE=$(basename "$TARGET_FILE") 13 | 14 | COUNT=0 15 | while [ -L "$TARGET_FILE" -a $COUNT -lt 100 ] 16 | do 17 | TARGET_FILE=$(readlink "$TARGET_FILE") 18 | cd "$(dirname "$TARGET_FILE")" 19 | TARGET_FILE=$(basename "$TARGET_FILE") 20 | COUNT=$(($COUNT + 1)) 21 | done 22 | 23 | if [ "$TARGET_FILE" == "." -o "$TARGET_FILE" == ".." ]; then 24 | cd "$TARGET_FILE" 25 | TARGET_FILEPATH= 26 | else 27 | TARGET_FILEPATH=/$TARGET_FILE 28 | fi 29 | 30 | # make sure we grab the actual windows path, instead of cygwin's path. 31 | if ! is_cygwin; then 32 | echo "$(pwd -P)/$TARGET_FILE" 33 | else 34 | echo $(cygwinpath "$(pwd -P)/$TARGET_FILE") 35 | fi 36 | ) 37 | } 38 | 39 | # TODO - Do we need to detect msys? 40 | 41 | # Uses uname to detect if we're in the odd cygwin environment. 42 | is_cygwin() { 43 | local os=$(uname -s) 44 | case "$os" in 45 | CYGWIN*) return 0 ;; 46 | *) return 1 ;; 47 | esac 48 | } 49 | 50 | # This can fix cygwin style /cygdrive paths so we get the 51 | # windows style paths. 52 | cygwinpath() { 53 | local file="$1" 54 | if is_cygwin; then 55 | echo $(cygpath -w $file) 56 | else 57 | echo $file 58 | fi 59 | } 60 | 61 | # Make something URI friendly 62 | make_url() { 63 | url="$1" 64 | local nospaces=${url// /%20} 65 | if is_cygwin; then 66 | echo "/${nospaces//\\//}" 67 | else 68 | echo "$nospaces" 69 | fi 70 | } 71 | 72 | # Detect if we should use JAVA_HOME or just try PATH. 73 | get_java_cmd() { 74 | if [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then 75 | echo "$JAVA_HOME/bin/java" 76 | else 77 | echo "java" 78 | fi 79 | } 80 | 81 | echoerr () { 82 | echo 1>&2 "$@" 83 | } 84 | vlog () { 85 | [[ $verbose || $debug ]] && echoerr "$@" 86 | } 87 | dlog () { 88 | [[ $debug ]] && echoerr "$@" 89 | } 90 | execRunner () { 91 | # print the arguments one to a line, quoting any containing spaces 92 | [[ $verbose || $debug ]] && echo "# Executing command line:" && { 93 | for arg; do 94 | if printf "%s\n" "$arg" | grep -q ' '; then 95 | printf "\"%s\"\n" "$arg" 96 | else 97 | printf "%s\n" "$arg" 98 | fi 99 | done 100 | echo "" 101 | } 102 | 103 | exec "$@" 104 | } 105 | addJava () { 106 | dlog "[addJava] arg = '$1'" 107 | java_args=( "${java_args[@]}" "$1" ) 108 | } 109 | addApp () { 110 | dlog "[addApp] arg = '$1'" 111 | sbt_commands=( "${app_commands[@]}" "$1" ) 112 | } 113 | addResidual () { 114 | dlog "[residual] arg = '$1'" 115 | residual_args=( "${residual_args[@]}" "$1" ) 116 | } 117 | addDebugger () { 118 | addJava "-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=$1" 119 | } 120 | addConfigOpts () { 121 | dlog "[addConfigOpts] arg = '$*'" 122 | for item in $* 123 | do 124 | addJava "$item" 125 | done 126 | } 127 | # a ham-fisted attempt to move some memory settings in concert 128 | # so they need not be messed around with individually. 129 | get_mem_opts () { 130 | local mem=${1:-1024} 131 | local meta=$(( $mem / 4 )) 132 | (( $meta > 256 )) || meta=256 133 | (( $meta < 1024 )) || meta=1024 134 | 135 | # default is to set memory options but this can be overridden by code section below 136 | memopts="-Xms${mem}m -Xmx${mem}m" 137 | if [[ "${java_version}" > "1.8" ]]; then 138 | extmemopts="-XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=${meta}m" 139 | else 140 | extmemopts="-XX:PermSize=64m -XX:MaxPermSize=${meta}m" 141 | fi 142 | 143 | if [[ "${java_opts}" == *-Xmx* ]] || [[ "${java_opts}" == *-Xms* ]] || [[ "${java_opts}" == *-XX:MaxPermSize* ]] || [[ "${java_opts}" == *-XX:ReservedCodeCacheSize* ]] || [[ "${java_opts}" == *-XX:MaxMetaspaceSize* ]]; then 144 | # if we detect any of these settings in ${java_opts} we need to NOT output our settings. 145 | # The reason is the Xms/Xmx, if they don't line up, cause errors. 146 | memopts="" 147 | extmemopts="" 148 | fi 149 | 150 | echo "${memopts} ${extmemopts}" 151 | } 152 | require_arg () { 153 | local type="$1" 154 | local opt="$2" 155 | local arg="$3" 156 | if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then 157 | die "$opt requires <$type> argument" 158 | fi 159 | } 160 | is_function_defined() { 161 | declare -f "$1" > /dev/null 162 | } 163 | 164 | # If we're *not* running in a terminal, and we don't have any arguments, then we need to add the 'ui' parameter 165 | detect_terminal_for_ui() { 166 | [[ ! -t 0 ]] && [[ "${#residual_args}" == "0" ]] && { 167 | addResidual "ui" 168 | } 169 | # SPECIAL TEST FOR MAC 170 | [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]] && [[ "${#residual_args}" == "0" ]] && { 171 | echo "Detected MAC OSX launched script...." 172 | echo "Swapping to UI" 173 | addResidual "ui" 174 | } 175 | } 176 | 177 | # Processes incoming arguments and places them in appropriate global variables. called by the run method. 178 | process_args () { 179 | while [[ $# -gt 0 ]]; do 180 | case "$1" in 181 | -h|-help) usage; exit 1 ;; 182 | -v|-verbose) verbose=1 && shift ;; 183 | -d|-debug) debug=1 && shift ;; 184 | -mem) require_arg integer "$1" "$2" && app_mem="$2" && shift 2 ;; 185 | -jvm-debug) 186 | if echo "$2" | grep -E ^[0-9]+$ > /dev/null; then 187 | addDebugger "$2" && shift 188 | else 189 | addDebugger 9999 190 | fi 191 | shift ;; 192 | -java-home) require_arg path "$1" "$2" && java_cmd="$2/bin/java" && shift 2 ;; 193 | -D*) addJava "$1" && shift ;; 194 | -J*) addJava "${1:2}" && shift ;; 195 | *) addResidual "$1" && shift ;; 196 | esac 197 | done 198 | 199 | is_function_defined process_my_args && { 200 | myargs=("${residual_args[@]}") 201 | residual_args=() 202 | process_my_args "${myargs[@]}" 203 | } 204 | } 205 | 206 | # Actually runs the script. 207 | run() { 208 | # TODO - check for sane environment 209 | 210 | # process the combined args, then reset "$@" to the residuals 211 | process_args "$@" 212 | detect_terminal_for_ui 213 | set -- "${residual_args[@]}" 214 | argumentCount=$# 215 | 216 | #check for jline terminal fixes on cygwin 217 | if is_cygwin; then 218 | stty -icanon min 1 -echo > /dev/null 2>&1 219 | addJava "-Djline.terminal=jline.UnixTerminal" 220 | addJava "-Dsbt.cygwin=true" 221 | fi 222 | 223 | # run sbt 224 | execRunner "$java_cmd" \ 225 | "-Dactivator.home=$(make_url "$activator_home")" \ 226 | $(get_mem_opts $app_mem) \ 227 | ${java_opts[@]} \ 228 | ${java_args[@]} \ 229 | -jar "$app_launcher" \ 230 | "${app_commands[@]}" \ 231 | "${residual_args[@]}" 232 | 233 | local exit_code=$? 234 | if is_cygwin; then 235 | stty icanon echo > /dev/null 2>&1 236 | fi 237 | exit $exit_code 238 | } 239 | 240 | # Loads a configuration file full of default command line options for this script. 241 | loadConfigFile() { 242 | cat "$1" | sed '/^\#/d' 243 | } 244 | 245 | ### ------------------------------- ### 246 | ### Start of customized settings ### 247 | ### ------------------------------- ### 248 | usage() { 249 | cat < [options] 251 | 252 | Command: 253 | ui Start the Activator UI 254 | new [name] [template-id] Create a new project with [name] using template [template-id] 255 | list-templates Print all available template names 256 | -h | -help Print this message 257 | 258 | Options: 259 | -v | -verbose Make this runner chattier 260 | -d | -debug Set sbt log level to debug 261 | -mem Set memory options (default: $sbt_mem, which is $(get_mem_opts $sbt_mem)) 262 | -jvm-debug Turn on JVM debugging, open at the given port. 263 | 264 | # java version (default: java from PATH, currently $(java -version 2>&1 | grep version)) 265 | -java-home Alternate JAVA_HOME 266 | 267 | # jvm options and output control 268 | -Dkey=val Pass -Dkey=val directly to the java runtime 269 | -J-X Pass option -X directly to the java runtime 270 | (-J is stripped) 271 | 272 | # environment variables (read from context) 273 | JAVA_OPTS Environment variable, if unset uses "" 274 | SBT_OPTS Environment variable, if unset uses "" 275 | ACTIVATOR_OPTS Environment variable, if unset uses "" 276 | 277 | In the case of duplicated or conflicting options, the order above 278 | shows precedence: environment variables lowest, command line options highest. 279 | EOM 280 | } 281 | 282 | ### ------------------------------- ### 283 | ### Main script ### 284 | ### ------------------------------- ### 285 | 286 | declare -a residual_args 287 | declare -a java_args 288 | declare -a app_commands 289 | declare -r real_script_path="$(realpath "$0")" 290 | declare -r activator_home="$(realpath "$(dirname "$real_script_path")")" 291 | declare -r app_version="1.3.2" 292 | 293 | declare -r app_launcher="${activator_home}/activator-launch-${app_version}.jar" 294 | declare -r script_name=activator 295 | java_cmd=$(get_java_cmd) 296 | declare -r java_opts=( "${ACTIVATOR_OPTS[@]}" "${SBT_OPTS[@]}" "${JAVA_OPTS[@]}" "${java_opts[@]}" ) 297 | userhome="$HOME" 298 | if is_cygwin; then 299 | # cygwin sets home to something f-d up, set to real windows homedir 300 | userhome="$USERPROFILE" 301 | fi 302 | declare -r activator_user_home_dir="${userhome}/.activator" 303 | declare -r java_opts_config_home="${activator_user_home_dir}/activatorconfig.txt" 304 | declare -r java_opts_config_version="${activator_user_home_dir}/${app_version}/activatorconfig.txt" 305 | 306 | # Now check to see if it's a good enough version 307 | declare -r java_version=$("$java_cmd" -version 2>&1 | awk -F '"' '/version/ {print $2}') 308 | if [[ "$java_version" == "" ]]; then 309 | echo 310 | echo No java installations was detected. 311 | echo Please go to http://www.java.com/getjava/ and download 312 | echo 313 | exit 1 314 | elif [[ ! "$java_version" > "1.6" ]]; then 315 | echo 316 | echo The java installation you have is not up to date 317 | echo Activator requires at least version 1.6+, you have 318 | echo version $java_version 319 | echo 320 | echo Please go to http://www.java.com/getjava/ and download 321 | echo a valid Java Runtime and install before running Activator. 322 | echo 323 | exit 1 324 | fi 325 | 326 | # if configuration files exist, prepend their contents to the java args so it can be processed by this runner 327 | # a "versioned" config trumps one on the top level 328 | if [[ -f "$java_opts_config_version" ]]; then 329 | addConfigOpts $(loadConfigFile "$java_opts_config_version") 330 | elif [[ -f "$java_opts_config_home" ]]; then 331 | addConfigOpts $(loadConfigFile "$java_opts_config_home") 332 | fi 333 | 334 | run "$@" 335 | --------------------------------------------------------------------------------