Permalink
Browse files

the classes inside the methods were very convenient but I kept gettin…

…g lost in the code

renamed and cleaned up a few things
  • Loading branch information...
1 parent e4eebad commit 4fd7914026946a4bb76430150318195f0f26330e @jrwest committed Feb 24, 2012
@@ -0,0 +1,42 @@
+package com.something.lift
+
+import net.liftweb.http.provider.HTTPContext
+import java.net.URL
+import java.io.InputStream
+import net.liftweb.common.{Empty, Box}
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: jordanrw
+ * Date: 2/23/12
+ * Time: 8:07 PM
+ */
+
+class HTTPNettyContext extends HTTPContext {
+
+ // netty has no context, so we assume root
+ def path: String = ""
+
+ // FIXME this should actually return the path to the resource @see{net.liftweb.http.provider.HTTPContext}
+ def resource(path: String): URL = null
+
+ // FIXME @see{net.liftweb.http.provider.HTTPContext}
+ def resourceAsStream(path: String): InputStream = throw new Exception("Not Yet Implemented")
+
+ // FIXME @see{net.liftweb.http.provider.HTTPContext}
+ def mimeType(path: String): Box[String] = Empty
+
+ /* All Methods Below Should Not Be Needed for Netty */
+
+ def initParam(name: String): Box[String] = Empty
+
+ def initParams: List[(String, String)] = Nil
+
+ def attribute(name: String): Box[Any] = Empty
+
+ def attributes: List[(String, Any)] = Nil
+
+ def setAttribute(name: String, value: Any) { }
+
+ def removeAttribute(name: String) { }
+}
@@ -0,0 +1,99 @@
+package com.something.lift
+
+import org.jboss.netty.handler.codec.http._
+import org.jboss.netty.channel._
+import net.liftweb.common.{Empty, Box}
+import net.liftweb.http.provider._
+import net.liftweb.http._
+import net.liftweb.util.{Helpers, Schedule, LoanWrapper}
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: jordanrw
+ * Date: 2/22/12
+ * Time: 10:04 PM
+ */
+
+object MyTypes {
+ type VarProvider = { def apply[T](session: Box[LiftSession], f: => T): T}
+
+}
+
+import MyTypes._
+
+class LiftChannelHandler(val nettyContext: HTTPNettyContext,
+ val transientVarProvider: VarProvider,
+ val reqVarProvider: VarProvider,
+ val liftLand: LiftServlet) extends SimpleChannelUpstreamHandler with HTTPProvider {
+
+ bootLift(Empty)
+
+ def context = nettyContext
+
+ /**
+ * Wrap the loans around the incoming request
+ */
+ private def handleLoanWrappers[T](f: => T): T = {
+ /*
+
+ FIXME -- this is a 2.5-ism
+ val wrappers = LiftRules.allAround.toList
+
+ def handleLoan(lst: List[LoanWrapper]): T = lst match {
+ case Nil => f
+ case x :: xs => x(handleLoan(xs))
+ }
+
+ handleLoan(wrappers)
+ */
+ f
+ }
+
+ override def messageReceived(ctx: ChannelHandlerContext, e: MessageEvent) {
+ val request = e.getMessage.asInstanceOf[HttpRequest]
+
+ if (HttpHeaders.is100ContinueExpected(request)) {
+ send100Continue(e);
+ }
+
+ def doNotHandled() {}
+
+ Schedule(() => {
+ try {
+ transientVarProvider(Empty,
+ reqVarProvider(Empty,{
+
+
+ val httpRequest: HTTPRequest = new NettyHttpRequest(request, ctx, nettyContext, this) // FIXME new HTTPRequestServlet(httpReq, this)
+ val httpResponse = new NettyHttpResponse(ctx)
+
+ handleLoanWrappers(service(httpRequest, httpResponse) {
+ doNotHandled()
+ })}))
+ } catch {
+ case excp => {
+ excp.printStackTrace
+ // FIXME placeholder code, do something correct here
+ val response: HttpResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)
+ val future = e.getChannel.write(response)
+ future.addListener(ChannelFutureListener.CLOSE)
+ }
+ }
+ })
+
+
+ }
+
+ override def exceptionCaught(ctx: ChannelHandlerContext, e: ExceptionEvent) {
+ println(e.getCause)
+ e.getChannel.close()
+ }
+
+ private def send100Continue(e: MessageEvent) {
+ val response: HttpResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE)
+ e.getChannel.write(response)
+ }
+
+
+}
+
@@ -20,16 +20,16 @@ import net.liftweb.common.{Empty, Box}
import MyTypes._
-object NothingServer extends App {
+object LiftNettyExampleServer extends App {
- val allChannels = new DefaultChannelGroup("nothing-server")
+ val allChannels = new DefaultChannelGroup("lift-netty-example-server")
private[this] val factory: ChannelFactory = new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()
)
- private def findObject(cls: String): Box[AnyRef] =
+ private def findObject(cls: String): Box[AnyRef] =
Helpers.tryo[Class[_]](Nil)(Class.forName(cls + "$")).flatMap {
c =>
Helpers.tryo {
@@ -38,21 +38,20 @@ object NothingServer extends App {
}
}
- val transientVarProvider: VarProvider =
+ val transientVarProvider: VarProvider =
findObject("net.liftweb.http.TransientRequestVarHandler").open_!.asInstanceOf[VarProvider]
val reqVarProvider: VarProvider =
findObject("net.liftweb.http.RequestVarHandler").open_!.asInstanceOf[VarProvider]
- val nettyContext = new NettyContext
-
+ val nettyContext = new HTTPNettyContext
val liftLand = new LiftServlet(nettyContext)
LiftRules.setContext(nettyContext)
private[this] val bootstrap = new ServerBootstrap(factory)
- val handler = new NothingServerHandler(nettyContext, transientVarProvider, reqVarProvider, liftLand)
+ val handler = new LiftChannelHandler(nettyContext, transientVarProvider, reqVarProvider, liftLand)
bootstrap.setPipelineFactory(new ChannelPipelineFactory {
def getPipeline: ChannelPipeline = Channels.pipeline(
@@ -0,0 +1,126 @@
+package com.something.lift
+
+import net.liftweb.http.provider._
+import net.liftweb.common.{Empty, Box}
+import java.io.InputStream
+import net.liftweb.http.{ParamHolder, LiftResponse, Req}
+import java.util.Locale
+import org.jboss.netty.channel.ChannelHandlerContext
+import org.jboss.netty.handler.codec.http.{HttpRequest, HttpHeaders}
+import java.net.{URI, InetSocketAddress}
+
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: jordanrw
+ * Date: 2/23/12
+ * Time: 8:31 PM
+ */
+
+/**
+ * The representation of a HTTP request state
+ */
+class NettyHttpRequest(request: HttpRequest,
+ channelContext: ChannelHandlerContext,
+ nettyContext: HTTPNettyContext,
+ val provider: HTTPProvider) extends HTTPRequest {
+
+ lazy val nettyLocalAddress = channelContext.getChannel.getLocalAddress.asInstanceOf[InetSocketAddress]
+ lazy val nettyRemoteAddress = channelContext.getChannel.getRemoteAddress.asInstanceOf[InetSocketAddress]
+
+ val contextPath = ""
+
+ // FIXME actually return the list of cookies
+ def cookies: List[HTTPCookie] = Nil
+
+ // FIXME
+ def authType: Box[String] = throw new Exception("Implement me")
+
+ // FIXME
+ def headers(name: String): List[String] = throw new Exception("Implement me")
+
+ // FIXME actually return the list of headers
+ def headers: List[HTTPParam] = Nil //TODO FIXME // throw new Exception("Implement me")
+
+ def context: HTTPContext = nettyContext
+
+ // FIXME actually return the content type
+ def contentType: Box[String] = Empty //FIXME // throw new Exception("Implement me")
+
+ def uri: String = request.getUri
+
+ // FIXME
+ def url: String = throw new Exception("Implement me")
+
+ def queryString: Box[String] = Box !! uri.splitAt(uri.indexOf("?") + 1)._2
+
+ // FIXME
+ def param(name: String): List[String] = throw new Exception("Implement me")
+
+ // FIXME
+ def params: List[HTTPParam] = throw new Exception("Implement me")
+
+ // FIXME
+ def paramNames: List[String] = throw new Exception("Implement me")
+
+ // FIXME the session is fake
+ def session: HTTPSession = new NettyHttpSession
+
+ // not needed for netter
+ def destroyServletSession() {}
+
+ // FIXME implement once sessions are supported
+ def sessionId: Box[String] = Empty
+
+ def remoteAddress: String = nettyRemoteAddress.toString
+
+ def remotePort: Int = nettyRemoteAddress.getPort
+
+ def remoteHost: String = nettyRemoteAddress.getHostName
+
+ def serverName: String = nettyLocalAddress.getHostName
+
+ def scheme: String = (new URI(request.getUri)).getScheme
+
+ def serverPort: Int = nettyLocalAddress.getPort
+
+ def method: String = request.getMethod.toString
+
+ // FIXME not really implemented, @dpp made it false when we started, left comment, "this should be trivial"
+ def suspendResumeSupport_? : Boolean = false
+
+ // FIXME not really implemented, @dpp made it None when we started, left comment, "trivial support"
+ def resumeInfo : Option[(Req, LiftResponse)] = None
+
+ // FIXME trivial support
+ def suspend(timeout: Long): RetryState.Value = throw new Exception("Implement me")
+
+ // FIXME trivial support
+ def resume(what: (Req, LiftResponse)): Boolean = throw new Exception("Implement me")
+
+ // FIXME
+ def inputStream: InputStream = throw new Exception("Implement me")
+
+ // FIXME actually detect multipart content
+ def multipartContent_? : Boolean = false
+
+ // FIXME
+ def extractFiles: List[ParamHolder] = throw new Exception("Implement me")
+
+ // FIXME actually detect locale
+ def locale: Box[Locale] = Empty
+
+ // FIXME
+ def setCharacterEncoding(encoding: String) = throw new Exception("Implement me")
+
+ /**
+ * Creates a new HTTPRequest instance as a copy of this one. It is used when
+ * snapshots of the current request context is created in order for this request object
+ * to be used on different threads (such as asynchronous template fragments processing).
+ * The new instance must not keep any reference to the container' instances.
+ */
+ // FIXME actually copy instance
+ def snapshot: HTTPRequest = this
+
+ def userAgent: Box[String] = Box !! request.getHeader(HttpHeaders.Names.USER_AGENT)
+}
@@ -0,0 +1,81 @@
+package com.something.lift
+
+import org.jboss.netty.handler.codec.http.{HttpResponseStatus, HttpVersion, DefaultHttpResponse, HttpResponse}
+import org.jboss.netty.buffer.ChannelBuffers
+import net.liftweb.http.provider.{HTTPParam, HTTPCookie, HTTPResponse}
+import java.io.OutputStream
+import org.jboss.netty.channel.{ChannelHandlerContext, ChannelFutureListener}
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: jordanrw
+ * Date: 2/23/12
+ * Time: 8:41 PM
+ */
+
+class NettyHttpResponse(ctx: ChannelHandlerContext) extends HTTPResponse {
+
+ lazy val nettyResponse: HttpResponse = {
+ val r = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)
+ r.setContent(ChannelBuffers.dynamicBuffer(1024)) // TODO this is just some random choice, do something more intelligent?
+ r
+ }
+
+ /**
+ * Add cookies to the response
+ *
+ * @param cookies - the list of response cookies
+ */
+ def addCookies(cookies: List[HTTPCookie]) {} // FIXME // throw new Exception("Implement me")
+
+ /**
+ * Encodes the URL such that it adds the session ID if it is necessary to the URL.
+ * It is implementation specific detail how/if to add the session informations. This will be used
+ * for URL rewriting purposes.
+ *
+ * @param url - the URL that needs to be analysed
+ */
+ def encodeUrl(url: String): String = url
+
+ /**
+ * Add a list of header parameters to the response object
+ *
+ * @param headers - the list of headers
+ */
+ def addHeaders(headers: List[HTTPParam]) {} // FIXME // throw new Exception("Implement me")
+
+ /**
+ * Sets the HTTP response status
+ *
+ * @param status - the HTTP status
+ */
+ def setStatus(status: Int) = nettyResponse.setStatus(HttpResponseStatus.valueOf(status)) //throw new Exception("Implement me")
+
+ /**
+ * Returns the HTTP response status that has been set with setStatus
+ * */
+ def getStatus: Int = nettyResponse.getStatus.getCode
+
+ /**
+ * Sets the HTTP response status
+ *
+ * @param status - the HTTP status
+ * @param reason - the HTTP reason phrase
+ */
+ def setStatusWithReason(status: Int, reason: String) = throw new Exception("Implement me")
+
+ /**
+ * @return - the OutputStream that can be used to send down o the client the response body.
+ */
+ def outputStream: OutputStream = new OutputStream {
+ // TODO: there is a probably a better impl, by override the other write methods.
+ def write(i: Int) {
+ nettyResponse.getContent.writeByte(i)
+ }
+
+ override def flush() {
+ val future = ctx.getChannel.write(nettyResponse)
+ future.addListener(ChannelFutureListener.CLOSE)
+ }
+ }
+}
Oops, something went wrong.

0 comments on commit 4fd7914

Please sign in to comment.