You are right. I will fine tune my determine which is a good question to ask mechanism :)
On Tue, Sep 8, 2009 at 12:54 PM, Timothy Perrett <timo...@getintheloop.eu>wrote: > > IMHO, you'd probably get better traction with such questions in a > wider audience on the main scala-user list over at EPFL... > > Cheers, Tim > > > On 8 Sep 2009, at 17:26, Jack Widman wrote: > > > Right. I will try to keep to the topic :) > > > > I actually found him and he quickly answered me. > > > > On Tue, Sep 8, 2009 at 12:24 PM, David Pollak < > feeder.of.the.be...@gmail.com > > > wrote: > > Jack, > > > > I'm not sure where N8han (the author of Databinder) hangs out, but > > it's not on the Lift list. :-( > > > > Sorry. > > > > David > > > > > > On Tue, Sep 8, 2009 at 8:58 AM, jack <jack.wid...@gmail.com> wrote: > > > > Please forgive me for including so much code but I have an important > > demo fast approaching and I'm kind of in a bind. I am using > > Databinders Dispatch http library which is a wrapper around Javas > > HttpClient library. I have included the Http class below. Does anyone > > see how to set the user-agent header. Once again I apologize and would > > be much obliged for any help. > > > > import collection.Map > > import collection.immutable.{Map => IMap} > > import util.DynamicVariable > > import java.io. > > {InputStream,OutputStream,BufferedInputStream,BufferedOutputStream} > > import java.net.URI > > import java.util.zip.GZIPInputStream > > > > import org.apache.http._ > > import org.apache.http.client._ > > import org.apache.http.impl.client.{DefaultHttpClient, > > BasicCredentialsProvider} > > import org.apache.http.client.methods._ > > import org.apache.http.client.entity.UrlEncodedFormEntity > > import org.apache.http.client.utils.URLEncodedUtils > > > > import org.apache.http.entity.StringEntity > > import org.apache.http.message.BasicNameValuePair > > import org.apache.http.protocol.HTTP.UTF_8 > > import org.apache.http.params.{HttpProtocolParams, BasicHttpParams} > > import org.apache.http.util.EntityUtils > > import org.apache.http.auth.{AuthScope, UsernamePasswordCredentials, > > Credentials} > > > > case class StatusCode(code: Int, contents:String) > > extends Exception("Exceptional resoponse code: " + code + "\n" + > > contents) > > > > /** Http access point. Standard instances to be used by a single > > thread. */ > > class Http { > > val credentials = new DynamicVariable[Option[(AuthScope, > > Credentials)]](None) > > val client = new ConfiguredHttpClient > > > > def credentialsProvider = new BasicCredentialsProvider { > > override def getCredentials(scope: AuthScope) = null > > } > > > > /** /** Info Logger for this instance, default returns Connfiggy if > > on classpath else console logger. */ > > lazy val log: Logger = try { > > new Logger { > > val delegate = net.lag.logging.Logger.get > > def info(msg: String, items: Any*) { delegate.info(msg, items: > > _*) } > > } > > } catch { > > case e: NoClassDefFoundError => new Logger { > > def info(msg: String, items: Any*) { > > println("INF: [console logger] dispatch: " + msg.format(items: > > _*)) > > } > > } > > } > > **/ > > /** Execute method for the given host, with logging. */ > > def execute(host: HttpHost, req: HttpUriRequest) = { > > //log.info("%s %s%s", req.getMethod, host, req.getURI) > > client.execute(host, req) > > } > > /** Execute for given optional parametrs, with logging. Creates > > local scope for credentials. */ > > val execute: (Option[HttpHost], Option[Credentials], HttpUriRequest) > > => HttpResponse = { > > case (Some(host), Some(creds), req) => > > client.credentials.withValue(Some((new AuthScope > > (host.getHostName, host.getPort), creds)))(execute(host, req)) > > case (None, Some(creds), _) => error("Credentials specified > > without explicit host") > > case (Some(host), _, req) => execute(host, req) > > case (_, _, req) => > > //log.info("%s %s", req.getMethod, req.getURI) > > client.execute(req) > > } > > /** Execute full request-response handler. */ > > def x[T](hand: Handler[T]): T = x(hand.request)(hand.block) > > /** Execute request and handle response codes, response, and entity > > in block */ > > def x [T](req: Request)(block: Handler.F[T]) = { > > val res = execute(req.host, req.creds, req.req) > > val ent = res.getEntity match { > > case null => None > > case ent => Some(ent) > > } > > try { block(res.getStatusLine.getStatusCode, res, ent) } > > finally { ent foreach (_.consumeContent) } > > } > > /** Apply Response Handler if reponse code returns true from chk. */ > > def when[T](chk: Int => Boolean)(hand: Handler[T]) = x(hand.request) > > { > > case (code, res, ent) if chk(code) => hand.block(code, res, ent) > > case (code, _, Some(ent)) => throw StatusCode(code, > > EntityUtils.toString(ent, UTF_8)) > > case (code, _, _) => throw StatusCode(code, "[no entity]") > > } > > /** Apply a custom block in addition to predefined response Handler. > > */ > > def also[A,B](hand: Handler[B])(block: Handler.F[A]) = > > x(hand.request) { (code, res, ent) => ( hand.block(code, res, > > ent), block(code, res, ent) ) } > > > > /** Apply handler block when response code is 200 - 204 */ > > def apply[T](hand: Handler[T]) = (this when {code => (200 to 204) > > contains code})(hand) > > } > > > > /** Nil request, useful to kick off a descriptors that don't have a > > factory. */ > > object /\ extends Request(None, None, Nil) > > > > /* Factory for requests from a host */ > > object :/ { > > def apply(hostname: String, port: Int): Request = > > new Request(Some(new HttpHost(hostname, port)), None, Nil) > > > > def apply(hostname: String): Request = new Request(Some(new HttpHost > > (hostname)), None, Nil) > > } > > > > /** Factory for requests from a directory, prepends '/'. */ > > object / { > > def apply(path: String) = /\ / path > > } > > > > object Request { > > /** Request transformer */ > > type Xf = HttpRequestBase => HttpRequestBase > > /** Updates the request URI with the given string-to-string > > function. (mutates request) */ > > def uri_xf(sxf: String => String)(req: HttpRequestBase) = { > > req.setURI(URI.create(sxf(req.getURI.toString))) > > req > > } > > } > > > > /** Request handler, contains request descriptor and a function to > > transform the result. */ > > case class Handler[T](request: Request, block: Handler.F[T]) extends > > Handlers { > > /** Create a new handler with block that receives all response > > parameters and > > this handler's block converted to parameterless function. */ > > def apply[R](next: (Int, HttpResponse, Option[HttpEntity], () => T) > > => R) = > > new Handler(request, {(code, res, ent) => > > next(code, res, ent, () => block(code, res, ent)) > > }) > > } > > > > object Handler { > > type F[T] = (Int, HttpResponse, Option[HttpEntity]) => T > > /** Turns a simple entity handler in into a full response handler > > that fails if no entity */ > > def apply[T](req: Request, block: HttpEntity => T): Handler[T] = > > Handler(req, { (code, res, ent) => ent match { > > case Some(ent) => block(ent) > > case None => error("response has no entity: " + res) > > } } ) > > } > > > > class Post(val values: Map[String, Any]) extends HttpPost { > > this setEntity new UrlEncodedFormEntity(Http.map2ee(values), UTF_8) > > } > > > > /** Request descriptor, possibly contains a host, credentials, and a > > list of transformation functions. */ > > class Request(val host: Option[HttpHost], val creds: Option > > [Credentials], val xfs: List[Request.Xf]) extends Handlers { > > > > /** Construct with path or full URI. */ > > def this(str: String) = this(None, None, Request.uri_xf(cur => cur + > > str)_ :: Nil) > > > > /** Construct as a clone, e.g. in class extends clause. */ > > def this(req: Request) = this(req.host, req.creds, req.xfs) > > > > def next(xf: Request.Xf) = new Request(host, creds, xf :: xfs) > > def next_uri(sxf: String => String) = next(Request.uri_xf(sxf)) > > > > def mimic(dest: HttpRequestBase)(req: HttpRequestBase) = { > > dest.setURI(req.getURI) > > dest.setHeaders(req.getAllHeaders) > > dest > > } > > > > // The below functions create new request descriptors based off of > > the current one. > > // Most are intended to be used as infix operators; those that don't > > take a parameter > > // have character names to be used with dot notation, e.g. /: > > ("example.com").HEAD.secure >>> {...} > > > > /** Set credentials to be used for this request; requires a host > > value :/(...) upon execution. */ > > def as (name: String, pass: String) = > > new Request(host, Some(new UsernamePasswordCredentials(name, > > pass)), xfs) > > > > /** Convert this to a secure (scheme https) request if not already > > */ > > def secure = new Request(host map { > > h => new HttpHost(h.getHostName, h.getPort, "https") // default > > port -1 works for either > > } orElse { error("secure requires an explicit host") }, creds, xfs) > > > > /** Combine this request with another. */ > > def <& (req: Request) = new Request(host orElse req.host, creds > > orElse req.creds, req.xfs ::: xfs) > > > > /** Combine this request with another handler. */ > > def >& [T] (other: Handler[T]) = new Handler(this <& other.request, > > other.block) > > > > /** Append an element to this request's path, joins with '/'. > > (mutates request) */ > > def / (path: String) = next_uri { _ + "/" + path } > > > > /** Add headers to this request. (mutates request) */ > > def <:< (values: Map[String, String]) = next { req => > > values foreach { case (k, v) => req.addHeader(k, v) } > > req > > } > > > > /* Add a gzip acceptance header */ > > def gzip = this <:< IMap("Accept-Encoding" -> "gzip") > > > > /** Put the given object.toString and return response wrapper. (new > > request, mimics) */ > > def <<< (body: Any) = next { > > val m = new HttpPut > > m setEntity new StringEntity(body.toString, UTF_8) > > HttpProtocolParams.setUseExpectContinue(m.getParams, false) > > mimic(m)_ > > } > > /** Post the given key value sequence and return response wrapper. > > (new request, mimics) */ > > def << (values: Map[String, Any]) = next { mimic(new Post(values)) > > _ } > > > > /** Add query parameters. (mutates request) */ > > def <<? (values: Map[String, Any]) = next_uri { uri => > > if (values.isEmpty) uri > > else uri + ( > > if (uri contains '?') '&' + Http.q_str(values) else (Http ? > > values) > > ) > > } > > > > // generators that change request method without adding parameters > > > > /** HTTP post request. (new request, mimics) */ > > def POST = next { mimic(new Post(IMap.empty))_ } > > > > /** HTTP delete request. (new request, mimics) */ > > def DELETE = next { mimic(new HttpDelete)_ } > > > > /** HTTP head request. (new request, mimics). See >:> to access > > headers. */ > > def HEAD = next { mimic(new HttpHead)_ } > > > > // end Request generators > > > > /** Builds underlying request starting with a blank get and applying > > transformers right to left. */ > > lazy val req = { > > val start: HttpRequestBase = new HttpGet("") > > (xfs :\ start) { (a,b) => a(b) } > > } > > > > /** @return URI based on this request, e.g. if needed outside > > Disptach. */ > > def to_uri = Http.to_uri(host, req) > > > > /** Use this request for trait Handlers */ > > val request = this > > } > > trait Handlers { > > /** the below functions produce Handlers based on this request > > descriptor */ > > val request: Request > > > > /** Handle InputStream in block, handle gzip if so encoded. */ > > def >> [T] (block: InputStream => T) = Handler(request, { ent => > > block ( > > if(ent.getContentEncoding != null && > > ent.getContentEncoding.getValue == "gzip") > > new GZIPInputStream(ent.getContent) > > else ent.getContent > > ) } ) > > /** Handle some non-huge response body as a String, in a block. */ > > def >- [T] (block: String => T) = >> { stm => block > > (scala.io.Source.fromInputStream(stm).mkString) } > > /** Return some non-huge response as a String. */ > > def as_str = >- { s => s } > > /** Write to the given OutputStream. */ > > def >>> [OS <: OutputStream](out: OS) = Handler(request, { ent => > > ent.writeTo(out); out }) > > /** Process response as XML document in block */ > > def <> [T] (block: xml.Elem => T) = >> { stm => block(xml.XML.load > > (stm)) } > > > > /** Process header as Map in block. Map returns empty set for header > > name misses. */ > > def >:> [T] (block: IMap[String, Set[String]] => T) = > > Handler(request, (_, res, _) => > > block((IMap[String, Set[String]]().withDefaultValue(Set()) /: > > res.getAllHeaders) { > > (m, h) => m + (h.getName -> (m(h.getName) + h.getValue)) > > } ) > > ) > > > > /** Ignore response body. */ > > def >| = Handler(request, (code, res, ent) => ()) > > > > /** Split into two request handlers, return results of each in > > tuple. */ > > def >+ [A, B] (block: Handlers => (Handler[A], Handler[B])) = { > > new Handler[(A,B)] ( request, { (code, res, opt_ent) => > > val (a, b) = block(new Handlers { val request = /\ }) > > (a.block(code, res, opt_ent), b.block(code,res,opt_ent)) > > } ) > > } > > } > > > > /** Basic extension of DefaultHttpClient defaulting to Http 1.1, UTF8, > > and no Expect-Continue. > > Scopes authorization credentials to particular requests thorugh a > > DynamicVariable. */ > > class ConfiguredHttpClient extends DefaultHttpClient { > > override def createHttpParams = { > > val params = new BasicHttpParams > > HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1) > > HttpProtocolParams.setContentCharset(params, UTF_8) > > HttpProtocolParams.setUseExpectContinue(params, false) > > params > > } > > val credentials = new DynamicVariable[Option[(AuthScope, > > Credentials)]](None) > > setCredentialsProvider(new BasicCredentialsProvider { > > override def getCredentials(scope: AuthScope) = credentials.value > > match { > > case Some((auth_scope, creds)) if scope.`match`(auth_scope) >= 0 > > => creds > > case _ => null > > } > > }) > > } > > > > /** Used by client APIs to build Handler or other objects via > > chaining, completed implicitly. > > * @see Http#builder2product */ > > trait Builder[T] { def product:T } > > > > /** May be used directly from any thread. */ > > object Http extends Http { > > import org.apache.http.conn.scheme. > > {Scheme,SchemeRegistry,PlainSocketFactory} > > import org.apache.http.conn.ssl.SSLSocketFactory > > import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager > > > > /** import to support e.g. Http("http://example.com/" >>> > > System.out) */ > > implicit def str2req(str: String) = new Request(str) > > > > implicit def builder2product[T](builder: Builder[T]) = > > builder.product > > > > override val client = new ConfiguredHttpClient { > > override def createClientConnectionManager() = { > > val registry = new SchemeRegistry() > > registry.register(new Scheme("http", > > PlainSocketFactory.getSocketFactory(), 80)) > > registry.register(new Scheme("https", > > SSLSocketFactory.getSocketFactory(), 443)) > > new ThreadSafeClientConnManager(getParams(), registry) > > } > > } > > /** Shutdown connection manager, threads. (Needed to close console > > cleanly.) */ > > def shutdown() = client.getConnectionManager.shutdown() > > > > /** Convert repeating name value tuples to list of pairs for > > httpclient */ > > def map2ee(values: Map[String, Any]) = java.util.Arrays asList ( > > values.toSeq map { case (k, v) => new BasicNameValuePair(k, > > v.toString) } toArray : _* > > ) > > /** @return %-encoded string for use in URLs */ > > def % (s: String) = java.net.URLEncoder.encode(s, UTF_8) > > > > /** @return %-decoded string e.g. from query string or form body */ > > def -% (s: String) = java.net.URLDecoder.decode(s, UTF_8) > > > > /** @return formatted and %-encoded query string, e.g. > > name=value&name2=value2 */ > > def q_str (values: Map[String, Any]) = URLEncodedUtils.format(map2ee > > (values), UTF_8) > > > > /** @return formatted query string prepended by ? unless values map > > is empty */ > > def ? (values: Map[String, Any]) = if (values.isEmpty) "" else "?" + > > q_str(values) > > > > /** @return URI built from HttpHost if present combined with a > > HttpClient request object. */ > > def to_uri(host: Option[HttpHost], req: HttpRequestBase) = > > URI.create(host.map(_.toURI).getOrElse("")).resolve(req.getURI) > > } > > > > > > > > > > > > -- > > 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 > > > > > > > > > > > > > > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Lift" group. To post to this group, send email to liftweb@googlegroups.com To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/liftweb?hl=en -~----------~----~----~----~------~----~------~--~---