{"action":"published","release":{"url":"https://api.github.com/repos/skinny-framework/skinny-framework/releases/1840253","assets_url":"https://api.github.com/repos/skinny-framework/skinny-framework/releases/1840253/assets","upload_url":"https://uploads.github.com/repos/skinny-framework/skinny-framework/releases/1840253/assets{?name,label}","html_url":"https://github.com/skinny-framework/skinny-framework/releases/tag/2.0.0.RC1","id":1840253,"tag_name":"2.0.0.RC1","target_commitish":"master","name":"version 2.0.0.RC1","draft":false,"author":{"login":"seratch","id":19658,"avatar_url":"https://avatars.githubusercontent.com/u/19658?v=3","gravatar_id":"","url":"https://api.github.com/users/seratch","html_url":"https://github.com/seratch","followers_url":"https://api.github.com/users/seratch/followers","following_url":"https://api.github.com/users/seratch/following{/other_user}","gists_url":"https://api.github.com/users/seratch/gists{/gist_id}","starred_url":"https://api.github.com/users/seratch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/seratch/subscriptions","organizations_url":"https://api.github.com/users/seratch/orgs","repos_url":"https://api.github.com/users/seratch/repos","events_url":"https://api.github.com/users/seratch/events{/privacy}","received_events_url":"https://api.github.com/users/seratch/received_events","type":"User","site_admin":false},"prerelease":false,"created_at":"2015-09-20T14:09:41Z","published_at":"2015-09-20T14:25:52Z","assets":[],"tarball_url":"https://api.github.com/repos/skinny-framework/skinny-framework/tarball/2.0.0.RC1","zipball_url":"https://api.github.com/repos/skinny-framework/skinny-framework/zipball/2.0.0.RC1","body":"This is the first RC version for 2.0.0 release.\r\n\r\n## Topics\r\n\r\n### Replace Scalatra with skinny-micro\r\n\r\nSkinny 2 has its own Servlet wrapper implementation. Skinny 2 won't be compatible with any versions of Scalatra. Skinny 1.x will keep compatible with Scalatra 2.3.x.\r\n\r\nhttps://github.com/skinny-framework/skinny-micro\r\n\r\nMostly DSLs are compatible but many improvements and minor API changes, renaming modules/classes and re-packaging have been applied. If you explicitly import `org.scalatra` package things into your applications, fixing packages or class/module names will be needed. Migration guide for details will come later.\r\n\r\n- SkinnyMicroServlet instead of ScalatraServlet\r\n- SkinnyMicroFilter instead of ScalatraFilter\r\n\r\nSkinny 2 has its own forked scalatra-test named skinny-micro-test.  If you're using ScalaTest, switching to skinny-micro-test will be so easy. Good to hear, your existing tests written with scalatra-test will work fine with Skinny 2 apps.\r\n\r\n#### A solution for Servlet request reuse issue\r\n\r\nWhen Servlet applications are running in async supported mode, Servlet containers sometimes **re-use** their HttpServletRequest objects in order to avoid the performance overhead of request object creation.\r\n\r\n- https://bugs.eclipse.org/bugs/show_bug.cgi?id=433321\r\n- https://github.com/scalatra/scalatra/pull/514\r\n- http://stackoverflow.com/questions/25626986/httpservletrequest-reuse\r\n\r\nskinny-micro wraps HttpServletRequest like this. \r\n\r\n[skinny/micro/request/StableHttpServletRequest.scala](https://github.com/skinny-framework/skinny-micro/blob/master/micro/src/main/scala/skinny/micro/request/StableHttpServletRequest.scala)\r\n\r\n`StableHttpServletRequest` basically works for you even when the original request has been recycled. Actually, it's difficult to make all the APIs stable. However, our StableHttpServletRequest makes basic metadata of the request, request attributes and request headers always stable. We believe that will be enough.\r\n\r\n#### A solution for accessing DynamicScope from other threads\r\n\r\nScalatra was originally designed to provide Sinatra-ish APIs for simple Servlet use cases. Traditionally Servlet apps allow thread-local approarch as same as other Java standard things.\r\n\r\n[Scalatra's DynamicScope](https://github.com/scalatra/scalatra/blob/v2.4.0.RC2-2/core/src/main/scala/org/scalatra/DynamicScope.scala) can be a cause of trouble especially when you're dealing with Future values. For example, this code is very fragile because of accessing other thread's variable from other threads.\r\n\r\n```scala\r\nclass Sample extends ScalatraServlet with FutureSupport {\r\n  get(\"/\") {\r\n     new AsyncResult {\r\n       override val is = {\r\n         // the \"request\" is a thread-local value of the main thread which is came from the above DynamicScope\r\n         // NullPointerException occasionally happens here\r\n         request.getContextPath \r\n       }\r\n     }\r\n  }\r\n}\r\n```\r\n\r\nScala 2.10 introduced Future APIs after successful Twitter's its own Future APIs and Finagle library. Thinking back now, that was a major event for Scala eco-system. Recently so many libraries and coding practices expect seamlessly using Future everywhere that the DynamicScope issue is no longer a small issue now.\r\n\r\nThe root cause of the issue is that we can easily (or unexpectedly) access the main-thread's thread-local variable via implicit conversions everywhere and we cannot disable it in some way.\r\n\r\nSo skinny-micro is going to solve the issue by following approarch:\r\n\r\n- By adding implicit `skinny.micro.Context` parameter to all the DSL methods, we no longer need to be careful to access unstable request reference (in the DynamicScope)\r\n\r\n- Add Async* traits to disable the global thread-local variable (e.g.) `AsyncSkinnyMicroServlet`, `AsyncSkinnyMicroFilter`\r\n\r\n```scala\r\nclass Sample extends AsyncSkinnyMicroServlet {\r\n  before() { implicit ctx =>\r\n    // never directly access dynamic scope here\r\n    contentType = \"application/json; charset=utf-8\"\r\n  }\r\n\r\n  get(\"/\") { implicit ctx =>\r\n    // never directly access dynamic scope here\r\n\r\n    // you no longer need to specify AsyncResult by yourself\r\n    Future {\r\n      // never directly access dynamic scope here\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nIf you need to mix non-async and async, define implicit value in the main thread side and fix `error: ambiguous implicit values` compilation errors:\r\n\r\n```scala\r\nclass Sample extends SkinnyMicroServlet {\r\n  get(\"/\") {\r\n    implicit val ctx = context\r\n\r\n    // you no longer need to specify AsyncResult by yourself\r\n    Future {\r\n      // fix compilation errors like this:\r\n      params(ctx).get(\"name\")\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n### Handy standalone web application builder\r\n\r\nskinny-micro-server has its own embedded Jetty server. This library will be very handy when you need to quickly build a small web application.\r\n\r\nhttps://github.com/skinny-framework/skinny-micro-heroku-example\r\n\r\nThe following is the minimum scalas example:\r\n\r\n- http://www.scala-sbt.org/0.13/docs/Scripts.html\r\n- https://github.com/skinny-framework/skinny-micro/tree/master/samples/src/main/scala/sample/standalone_app\r\n\r\n```scala\r\n#!/usr/bin/env scalas\r\n/***\r\nscalaVersion := \"2.11.7\"\r\nresolvers += \"sonatype releases\" at \"https://oss.sonatype.org/content/repositories/releases\"\r\nlibraryDependencies += \"org.skinny-framework\" %% \"skinny-micro-server\" % \"0.9.12\"\r\n*/\r\nimport skinny.micro._\r\nimport scala.concurrent._\r\n\r\nWebServer.mount(new WebApp {\r\n  get(\"/\") {\r\n    val name = params.getOrElse(\"name\", \"Anonymous\")\r\n    s\"Hello, $name\"\r\n  }\r\n}).mount(new AsyncWebApp {\r\n  get(\"/async\") { implicit ctx =>\r\n    Future {\r\n      responseAsJSON(params)\r\n    }\r\n  }\r\n}).port(8081).run()\r\n```\r\n\r\nNOTICE: `WebApp` is a type alias for `SkinnyMicroFilter` and `AsyncWebApp` is one for `AsyncSkinnyMicroFilter`.\r\n"}}