Dynamic Image generation / HttpServletResponse

122 views
Skip to first unread message

Thomas Rynne

unread,
Mar 25, 2009, 5:38:22 PM3/25/09
to Lift
Hi,
I want to dynamically generate images (actually a graph). I could
write a seperate servlet for this but I'd like easy access to the
Mapper classes and the logged in User etc so would prefer to write it
as a method in lift.

Is there a hook for this? I suppose I essentially want direct acccess
to the httpresponse.

I found some discussion of this here:
http://groups.google.com/group/liftweb/browse_thread/thread/9d6f61f69a20765/d98a32e89e87d317

but I don't know if it was ever implemented, and need some pointers/
documentation if it has been.

thanks for any advice,
Thomas

David Pollak

unread,
Mar 25, 2009, 6:00:02 PM3/25/09
to lif...@googlegroups.com
Oddly enough, I'm working on code like this right now... I'll post what I can.
--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp

Derek Chen-Becker

unread,
Mar 25, 2009, 6:17:17 PM3/25/09
to lif...@googlegroups.com

Timothy Perrett

unread,
Mar 25, 2009, 7:02:06 PM3/25/09
to Lift Google Group
If you'd like graphing, depending on your use case perhaps check out
the flot graph widget in lift-widgets

Sent from my iPhone

David Pollak

unread,
Mar 25, 2009, 7:14:12 PM3/25/09
to lif...@googlegroups.com
Here's some code to serve an image out of the database.  Here's the Mapper definition:

class Image extends LongKeyedMapper[Image] with IdPK {
  def getSingleton = Image

  object image extends MappedBinary(this)
  object lookup extends MappedUniqueId(this, 32) {
    override def dbIndexed_? = true
  }
  object saveTime extends MappedLong(this) {
    override def defaultValue = millis
  }
  object mimeType extends MappedString(this, 256)
}

object Image extends Image with LongKeyedMetaMapper[Image]

And here's the code that serves the image:

object ImageLogic {
  object TestImage {
    def unapply(in: String): Option[Image] =
    Image.find(By(Image.lookup, in.trim))
  }

  def matcher: LiftRules.DispatchPF = {
    case r @ Req("image_logic" :: TestImage(img) ::
                 Nil, _, GetRequest) => () => servImage(img, r)
  }

  def servImage(img: Image, r: Req): Box[LiftResponse] = {
    if (r.testIfModifiedSince(img.saveTime))
    Full(InMemoryResponse(new Array[Byte](0),
                          List("Last-Modified" ->
                               toInternetDate(img.saveTime.is)), Nil, 304))
    else Full(InMemoryResponse(img.image.is,
                               List("Last-Modified" ->
                                    toInternetDate(img.saveTime.is),
                                    "Content-Type" -> img.mimeType.is,
                                    "Content-Length" ->
                                    img.image.is.length.toString), Nil, 200))
  }
}

In Boot:

     LiftRules.dispatch.append(ImageLogic.matcher)

Does this help?

Thanks,

David

Viktor Klang

unread,
Mar 26, 2009, 4:53:18 AM3/26/09
to lif...@googlegroups.com
For Graphs I'd recommend Flot :)
--
Viktor Klang
Senior Systems Analyst

Thomas Rynne

unread,
Mar 30, 2009, 1:27:42 PM3/30/09
to Lift
On Mar 26, 12:14 am, David Pollak <feeder.of.the.be...@gmail.com>
wrote:
> Here's some code to serve an image out of the database.
> ...
> Does this help?

Yes it does. I've got it working now.

Thanks, Thomas

Eirik

unread,
Aug 27, 2010, 3:38:49 AM8/27/10
to David Pollak, lif...@googlegroups.com
Sorry, I was unable to reply to the thread so I'm cc'ing
lif...@googlegroups.com

> Here's some code to serve an image out of the database.

What is the preferred way to dynamically serve content from any url,
preferrably directly from a stateful snippet? After boot time, you
cannot call LiftRules.dispatch.prepend(...), so it seems the only way
is to store content in a singleton. If this is the only way, is there
a way to add a callback to run after the content has been served (so
that I can remove it afterwards)? Code samples much appreciated :)
Here's an example of how I was hoping to do this:

class DynamicContentService extends StatefulSnippet {
override def dispatch = {
case "content" => content _
}

def content(x: NodeSeq): NodeSeq = {
bind("content", xhtml,
"somefield" -> text(...),
"submit" -> ajaxSubmit("Download", () => {
val response:LiftResponse = createResponse(createContent)
val url:String = urlFor(response)
S.serve(url, response, S.unserve(ur))
JsRaw("download(url)")
}))
}
}

... where S.serve is an imaginary function that takes a String for an
url, a LiftResponse to serve, and a callback after response has been
served.

Regards, Eirik

On Mar 26 2009, 1:14 am, David Pollak <feeder.of.the.be...@gmail.com>
wrote:

> On Wed, Mar 25, 2009 at 2:38 PM, Thomas Rynne <thomas.ry...@gmail.com>wrote:
>
>
>
>
>
> > Hi,
> >  I want to dynamically generate images (actually a graph). I could
> > write a seperate servlet for this but I'd like easy access to the
> > Mapper classes and the logged in User etc so would prefer to write it
> > as a method in lift.
>
> > Is there a hook for this? I suppose I essentially want direct acccess
> > to the httpresponse.
>
> > I found some discussion of this here:
>

> >http://groups.google.com/group/liftweb/browse_thread/thread/9d6f61f69...


>
> > but I don't know if it was ever implemented, and need some pointers/
> > documentation if it has been.
>
> > thanks for any advice,
> > Thomas
>
> --
> Lift, the simply functional web frameworkhttp://liftweb.net

> Beginning Scalahttp://www.apress.com/book/view/1430219890

Ross Mellgren

unread,
Aug 27, 2010, 9:20:49 AM8/27/10
to lif...@googlegroups.com, David Pollak, lif...@googlegroups.com
Keep in mind that dispatching is a list of partial functions. Even though you can't add or remove functions from the list after boot, you can make your function handle different resources over time.

Something like

LiftRules.dispatch.prepend(MyServer.dispatch)


object MyServer {
private var resources: Map[List[String], String] = Map.empty

def serve(path: List[String], body: String): Unit = resources += ((path -> body))

val dispatch = resources andThen { body => InMemoryResponse(body.getBytes, Nil, Nil, 200) }
}

Now this doesn't handle expiring/deleting things, and incorrectly converts the body string to bytes using platform default encoding, and doesn't have a callback and isn't threadsafe, but I'm typing this on an iPad so hopefully it'll give you some ideas as to what's possible.

There's a couple different strategies by the way. I know DPP has been working on a CMS module which does something like this and he's previously written an example called WikiStuff that also does something similar -- http://github.com/lift/lift/blob/master/examples/example/src/main/scala/net/liftweb/example/lib/WikiStuff.scala

HTH,
-Ross

> --
> You received this message because you are subscribed to the Google Groups "Lift" group.
> To post to this group, send email to lif...@googlegroups.com.
> To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
>

David Pollak

unread,
Aug 27, 2010, 9:42:38 AM8/27/10
to lif...@googlegroups.com
On Fri, Aug 27, 2010 at 12:38 AM, Eirik <eiri...@gmail.com> wrote:
Sorry, I was unable to reply to the thread so I'm cc'ing
lif...@googlegroups.com

> Here's some code to serve an image out of the database.
What is the preferred way to dynamically serve content from any url,
preferrably directly from a stateful snippet?

Snippets are for translating NodeSeq => NodeSeq, not for serving arbitrary content (like an image).  Snippets are not bound to a URL, but invoked by markup in your view.  StatefulSnippets are just that... the same instance is used across invocations of the view if you are using forms so that you can put state in the StatefulSnippet's instance variables.
 
After boot time, you
cannot call LiftRules.dispatch.prepend(...), so it seems the only way
is to store content in a singleton.

I don't understand.  If you want to create a unique URL for the current session that intercepts a request, that's possible, but it's generally used to respond to callbacks from the likes of PayPal and Facebook (having a unique URL callback gives you increased security.)  If you want to have a fixed URL that defines variable context, you just compute the content to be returned in the partial function passed to LiftRules.dispatch
 
If this is the only way, is there
a way to add a callback to run after the content has been served (so
that I can remove it afterwards)? Code samples much appreciated :)

What are you specifically trying to do?  What's your use case?



--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Blog: http://goodstuff.im
Surf the harmonics

Eirik Rosvold Larsen

unread,
Aug 30, 2010, 4:52:06 AM8/30/10
to lif...@googlegroups.com
What are you specifically trying to do?  What's your use case?
I'm generating a KML-file for the user to download based on input from an ajax-form. What would be the best way to accomplish this with Lift?

Regards, Eirik

--

Timothy Perrett

unread,
Aug 30, 2010, 6:30:58 AM8/30/10
to lif...@googlegroups.com
Use a DispatchPF.

https://www.assembla.com/spaces/liftweb/wiki?id=liftweb&wiki_id=REST_Web_Services

Essentially you are making a callable URL as it will be invoked by the client side JS. Perhaps its stateless, perhaps it isnt... either way, dispatching is the way to go here.

Cheers, Tim

Eirik Rosvold Larsen

unread,
Aug 30, 2010, 7:01:33 AM8/30/10
to lif...@googlegroups.com
Got it working with dispatchPF. Thanks.

Regards, Eirik

Timothy Perrett

unread,
Aug 30, 2010, 7:19:46 AM8/30/10
to lif...@googlegroups.com
You're welcome :-)

Sergey Trofimov

unread,
Jun 13, 2011, 3:49:50 AM6/13/11
to lif...@googlegroups.com
David, should not be condition r.testIfModifiedSince(img.saveTime) swapped in your sample?
I mean that if r.testIfModifiedSince(img.saveTime) is true then we serve full image otherwise we serve only "Last-Modified" header.
Reply all
Reply to author
Forward
0 new messages