Skip to content

Commit

Permalink
Merge branch 'hotfix-0.8.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
dlecan committed Oct 31, 2012
2 parents 0cfc769 + 3d605e9 commit 49024ce
Show file tree
Hide file tree
Showing 16 changed files with 227 additions and 123 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ project/target
.cache
.settings
.target
bin
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# WAR Plugin for Play framework 2.0

Current version: 0.8
Current version: 0.8.1

Project-status: BETA

Expand All @@ -25,9 +25,9 @@ Other references built with Play 2 and Play2War:
## Compatibiity with Play2
* Play 2.0.0 : Play2War 0.3, 0.4
* Play 2.0.1 : Play2War 0.5
* Play 2.0.2 : Play2War 0.6, 0.7.x, 0.8.x
* Play 2.0.3 : Play2War 0.7.x, 0.8.x
* Play 2.0.4 : Play2War 0.7.x, 0.8.x
* Play 2.0.2 : Play2War 0.8.x
* Play 2.0.3 : Play2War 0.8.x
* Play 2.0.4 : Play2War 0.8.x

## What's new ?

Expand Down Expand Up @@ -159,7 +159,7 @@ In ``APP_HOME/project/plugins.sbt``, add:
```scala
resolvers += "Play2war plugins release" at "http://repository-play-war.forge.cloudbees.com/release/"

addSbtPlugin("com.github.play2war" % "play2-war-plugin" % "0.8")
addSbtPlugin("com.github.play2war" % "play2-war-plugin" % "0.8.1")
```
### Import Play2War SBT settings

Expand Down Expand Up @@ -215,6 +215,8 @@ Create a file ``APP_HOME/conf/logger.xml`` with the following content :
<root level="ERROR">
<appender-ref ref="STDOUT" />
</root>

</configuration>
```

</configuration>
Expand Down
30 changes: 21 additions & 9 deletions project-code/core/common/src/main/scala/Play2CommonServlet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,17 @@ import play.core._
import server.Server
import scala.collection.JavaConverters._
import java.util.concurrent.atomic.AtomicBoolean
import java.net.URLDecoder

object Play2Servlet {
object GenericPlay2Servlet {
var playServer: Play2WarServer = null
var configuration: Configuration = null
}

/**
* Mother class for all servlet implementations for Play2.
*/
abstract class Play2Servlet[T] extends HttpServlet with ServletContextListener {

protected def getHttpParameters(request: HttpServletRequest): Map[String, Seq[String]]
abstract class GenericPlay2Servlet[T] extends HttpServlet with ServletContextListener {

protected def getPlayHeaders(request: HttpServletRequest): Headers

Expand Down Expand Up @@ -71,7 +70,7 @@ abstract class Play2Servlet[T] extends HttpServlet with ServletContextListener {

val execContext: T = onBeginService(servletRequest, servletResponse)

val server = Play2Servlet.playServer
val server = GenericPlay2Servlet.playServer

// val keepAlive -> non-sens
// val websocketableRequest -> non-sens
Expand Down Expand Up @@ -357,6 +356,19 @@ abstract class Play2Servlet[T] extends HttpServlet with ServletContextListener {

}

protected def getHttpParameters(request: HttpServletRequest): Map[String, Seq[String]] = {
request.getQueryString match {
case null | "" => Map.empty
case queryString => queryString.replaceFirst("^?", "").split("&").map(_.split("=")).map { array =>
array.length match {
case 0 => None
case 1 => Some(URLDecoder.decode(array(0), "UTF-8") -> "")
case _ => Some(URLDecoder.decode(array(0), "UTF-8") -> URLDecoder.decode(array(1), "UTF-8"))
}
}.flatten.groupBy(_._1).map { case (key, value) => key -> value.map(_._2).toSeq }.toMap
}
}

override def contextInitialized(e: ServletContextEvent) = {
e.getServletContext.log("PlayServletWrapper > contextInitialized")

Expand All @@ -372,9 +384,9 @@ abstract class Play2Servlet[T] extends HttpServlet with ServletContextListener {

val application = new WarApplication(classLoader, Mode.Prod, julHandlers)

Play2Servlet.configuration = application.get.right.map { _.configuration }.right.getOrElse(Configuration.empty)
GenericPlay2Servlet.configuration = application.get.right.map { _.configuration }.right.getOrElse(Configuration.empty)

Play2Servlet.playServer = new Play2WarServer(application)
GenericPlay2Servlet.playServer = new Play2WarServer(application)
}

override def contextDestroyed(e: ServletContextEvent) = {
Expand All @@ -390,10 +402,10 @@ abstract class Play2Servlet[T] extends HttpServlet with ServletContextListener {
}

private def stopPlayServer(sc: ServletContext) = {
Option(Play2Servlet.playServer).map {
Option(GenericPlay2Servlet.playServer).map {
s =>
s.stop()
Play2Servlet.playServer = null
GenericPlay2Servlet.playServer = null
sc.log("Play server stopped")
} // if playServer is null, nothing to do
}
Expand Down
62 changes: 23 additions & 39 deletions project-code/core/servlet25/src/main/scala/Play2Servlet25.scala
Original file line number Diff line number Diff line change
@@ -1,71 +1,55 @@
package play.core.server.servlet25

import javax.servlet._
import javax.servlet.http._
import java.io._
import java.util.Arrays

import play.api._
import play.api.mvc._
import play.api.http._
import play.api.http.HeaderNames._
import play.api.libs.iteratee._
import play.api.libs.iteratee.Input._
import play.api.libs.concurrent._
import play.core._
import play.core.server.servlet._
import play.core.server.servlet25.Play2Servlet._
import server.Server

import scala.collection.JavaConverters._
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import play.api.Logger
import play.core.server.servlet.GenericPlay2Servlet
import play.core.server.servlet.RichHttpServletRequest
import play.core.server.servlet.RichHttpServletResponse

object Play2Servlet {

// 30 minutes in milliseconds
// val WAIT_TIMEOUT = 30 * 60 * 1000
val WAIT_TIMEOUT = 10 * 1000
val DEFAULT_TIMEOUT = 10 * 1000

val syncTimeout = GenericPlay2Servlet.configuration.getInt("servlet25.synctimeout").getOrElse(DEFAULT_TIMEOUT)
Logger("play").debug("Sync timeout for HTTP requests: " + syncTimeout + " seconds")
}

class Play2Servlet extends play.core.server.servlet.Play2Servlet[Tuple3[HttpServletRequest, HttpServletResponse, Object]] with Helpers {
class Play2Servlet extends GenericPlay2Servlet[Tuple3[HttpServletRequest, HttpServletResponse, Object]] with Helpers {

protected override def onBeginService(request: HttpServletRequest, response: HttpServletResponse): Tuple3[HttpServletRequest, HttpServletResponse, Object] = {
(request, response, new Object())
(request, response, new Object())
}

protected override def onFinishService(execContext: Tuple3[HttpServletRequest, HttpServletResponse, Object]) = {
execContext._3.synchronized {
execContext._3.wait(WAIT_TIMEOUT)
execContext._3.wait(Play2Servlet.syncTimeout)
}
}

protected override def onHttpResponseComplete(execContext: Tuple3[HttpServletRequest, HttpServletResponse, Object]) = {
execContext._3.synchronized {
execContext._3.notify()
}
}

protected override def getHttpParameters(request: HttpServletRequest): Map[String, Seq[String]] = {
val parameterMap = request.getParameterMap.asInstanceOf[java.util.Map[String, Array[String]]].asScala
Map.empty[String, Seq[String]] ++ parameterMap.mapValues(Arrays.asList(_: _*).asScala)
}


protected override def getHttpRequest(executionContext: Tuple3[HttpServletRequest, HttpServletResponse, Object]): RichHttpServletRequest = {
new RichHttpServletRequest {
def getRichInputStream(): Option[java.io.InputStream] = {
Option(executionContext._1.getInputStream)
}
}
}

protected override def getHttpResponse(executionContext: Tuple3[HttpServletRequest, HttpServletResponse, Object]): RichHttpServletResponse = {
new RichHttpServletResponse {
def getRichOutputStream: Option[java.io.OutputStream] = {
Option(executionContext._2.getOutputStream)
}
def getHttpServletResponse: Option[HttpServletResponse] = {
Option(executionContext._2)
}
def getRichOutputStream: Option[java.io.OutputStream] = {
Option(executionContext._2.getOutputStream)
}

def getHttpServletResponse: Option[HttpServletResponse] = {
Option(executionContext._2)
}
}
}

Expand Down
41 changes: 16 additions & 25 deletions project-code/core/servlet30/src/main/scala/Play2Servlet30.scala
Original file line number Diff line number Diff line change
@@ -1,33 +1,28 @@
package play.core.server.servlet30

import javax.servlet._
import javax.servlet.annotation._
import javax.servlet.http._
import java.io._
import java.util.concurrent.atomic._
import java.util.Arrays

import play.api._
import play.api.mvc._
import play.api.http._
import play.api.http.HeaderNames._
import play.api.libs.iteratee._
import play.api.libs.iteratee.Input._
import play.api.libs.concurrent._
import play.core._
import play.core.server.servlet._
import server.Server

import scala.collection.JavaConverters._
import java.io.InputStream
import java.io.OutputStream
import java.util.concurrent.atomic.AtomicBoolean

import javax.servlet.AsyncContext
import javax.servlet.AsyncEvent
import javax.servlet.annotation.WebListener
import javax.servlet.annotation.WebServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import play.api.Logger
import play.core.server.servlet.GenericPlay2Servlet
import play.core.server.servlet.RichHttpServletRequest
import play.core.server.servlet.RichHttpServletResponse

object Play2Servlet {
val asyncTimeout = play.core.server.servlet.Play2Servlet.configuration.getInt("servlet30.asynctimeout").getOrElse(-1)
val asyncTimeout = GenericPlay2Servlet.configuration.getInt("servlet30.asynctimeout").getOrElse(-1)
Logger("play").debug("Async timeout for HTTP requests: " + asyncTimeout + " seconds")
}

@WebServlet(name = "Play", urlPatterns = Array { "/" }, asyncSupported = true)
@WebListener
class Play2Servlet extends play.core.server.servlet.Play2Servlet[Tuple2[AsyncContext, AsyncListener]] with Helpers {
class Play2Servlet extends GenericPlay2Servlet[Tuple2[AsyncContext, AsyncListener]] with Helpers {

protected override def onBeginService(request: HttpServletRequest, response: HttpServletResponse): Tuple2[AsyncContext, AsyncListener] = {
val asyncListener = new AsyncListener(request.toString)
Expand All @@ -45,10 +40,6 @@ class Play2Servlet extends play.core.server.servlet.Play2Servlet[Tuple2[AsyncCon
execContext._1.complete
}

protected override def getHttpParameters(request: HttpServletRequest): Map[String, Seq[String]] = {
Map.empty[String, Seq[String]] ++ request.getParameterMap.asScala.mapValues(Arrays.asList(_: _*).asScala)
}

protected override def getHttpRequest(execContext: Tuple2[AsyncContext, AsyncListener]): RichHttpServletRequest = {
new RichHttpServletRequest {
def getRichInputStream(): Option[InputStream] = {
Expand Down
22 changes: 16 additions & 6 deletions project-code/integration-tests/src/test/scala/AllTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,11 @@ abstract class AbstractPlay2WarTests extends FeatureSpec with GivenWhenThen with
******************
*/

feature("The container should query parameters") {
feature("The container should handle GET/POST parameters") {

scenario("Container reads GET parameters") {

val page = givenWhenGet("a page", "/echo", parameters = Map("param1" -> "value1", "param2" -> "value2"))
val page = givenWhenGet("a page", "/echoGetParameters", parameters = Map("param1" -> "value1", "param2" -> "value2"))

then("page body should contain parameters values")
page.map { p =>
Expand All @@ -202,7 +202,7 @@ abstract class AbstractPlay2WarTests extends FeatureSpec with GivenWhenThen with

scenario("Container reads POST parameters") {

val page = givenWhenGet("a page", "/echo", method = "POST", parameters = Map("param1" -> "value1", "param2" -> "value2"))
val page = givenWhenGet("a page", "/echoPostParameters", method = "POST", parameters = Map("param1" -> "value1", "param2" -> "value2"))

then("page body should contain parameters values")
page.map { p =>
Expand Down Expand Up @@ -366,8 +366,8 @@ abstract class AbstractPlay2WarTests extends FeatureSpec with GivenWhenThen with

feature("The container must handle POST requests with 'multipart/form-data' enctype") {

// 2 routes to test
List("/upload", "/upload2").foreach {
// routes where to test file upload
List("/upload", "/upload2", "/uploadJava", "/uploadJava2").foreach {
case (route) => {

scenario("container sends an image to " + route) {
Expand Down Expand Up @@ -420,6 +420,7 @@ class Tomcat7027Tests extends AbstractTomcat7x {
@RunWith(classOf[JUnitRunner])
class Tomcat6xTests extends AbstractPlay2WarTests with Servlet25Container {
override def containerUrl = "http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.35/bin/apache-tomcat-6.0.35.tar.gz"
override def containerFileNameInCloudbeesCache = Option("apache-tomcat-6.0.35.tar.gz")
override def containerName = "tomcat6x"
}

Expand All @@ -431,17 +432,26 @@ class Tomcat7027Tests extends AbstractTomcat7x {
@RunWith(classOf[JUnitRunner])
class Jetty7xTests extends AbstractPlay2WarTests with Servlet25Container {
override def containerUrl = "http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/7.6.5.v20120716/jetty-distribution-7.6.5.v20120716.tar.gz"
override def containerFileNameInCloudbeesCache = Option("jetty-distribution-7.6.5.v20120716.tar.gz")
override def containerName = "jetty7x"
}

// @RunWith(classOf[JUnitRunner])
// class Tomcat7029Tests extends AbstractTomcat7x {
// override def tomcatVersion = "7.0.29"
// override def containerFileNameInCloudbeesCache = Option("apache-tomcat-7.0.29.zip")
// }

@RunWith(classOf[JUnitRunner])
class Tomcat7029Tests extends AbstractTomcat7x {
override def tomcatVersion = "7.0.29"
override def tomcatVersion = "7.0.32"
override def containerFileNameInCloudbeesCache = Option("apache-tomcat-7.0.32.zip")
}

@RunWith(classOf[JUnitRunner])
class Jetty8xTests extends AbstractPlay2WarTests with Servlet30Container {
override def containerUrl = "http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/8.1.3.v20120416/jetty-distribution-8.1.3.v20120416.tar.gz"
override def containerFileNameInCloudbeesCache = Option("jetty-distribution-8.1.3.v20120416.tar.gz")
override def containerName = "jetty8x"
}

Expand Down
Loading

0 comments on commit 49024ce

Please sign in to comment.