scala play how to pass variables to page - scala

In Scala + Play, how to put a variable into response ?
In page
#lastName #firstName
In application controller:
def index = Action {
implicit request =>{
request.setAttribute("lastName", "john"); // not work
Ok(views.html.index("xxx"))
}
}
if in java servlet , we can do this way:
request.setAttribute("name", "value");
request.getRequestDispatcher("page.jsp").forward(request, response);
how to do the same in Scala + Play ?

You want to use view/page variables.
In your view:
#(myStringVar: String)
<b>Hello #myStringVar</b>
Your controller:
def index = Action {
implicit request => {
Ok(views.html.index(myStringVar = "Ooo!"))
}
}
Ref: https://playframework.com/documentation/2.5.x/ScalaTemplates#Overview

Related

How to proxy an HTTP method with play framework 2.5?

I have 2 simple APIs:
GET /users/me/photos controllers.api.UserController.getMyPhotos
GET /users/:userId/photos controllers.api.UserController.getPhotos(userId: Int)
Here's getPhotos:
def getPhotos(userId: Int) = SecuredAction.async {
logger.info(s"Searching for user $userId's photos")
userPhotosRepo.findByUserId(userId).map {
photos => Ok(Json.toJson(photos))
}
}
Here's getMyPhotos:
def getMyPhotos = SecuredAction.async { request =>
request.identity.id.map { currentUserId =>
logger.info(s"Searching for current user's photos")
getPhotos(currentUserId) // doesn't work
}.getOrElse(Future.successful(InternalServerError))
}
How can I make getMyPhotos proxy through to getPhotos without creating a helper method they both call?
Here you can use reverse routing provided by Play Framework
[full package].routes.[controller].[method]
In your case
routes.api.UserController.getPhotos(request.identity.id)
If you want the result of first action
val ans: Result = Redirect(routes.api.UserController.getPhotos(request.identity.id))
I hope that's what you were trying to ask.
EDIT:
For your concern this should be a proper way to do it
def getPhotos(userId: Long) = SecuredAction.async {
userPhotosRepo findByUserId(userId) map {
photos => Ok(Json.toJson(photos))
}
}
def getMyPhotos = SecuredAction.async { request =>
request.identity.id map { id =>
Redirect(routes.HomeController.getPhotos(id))
}
}

Dynamically constructing closures from a map?

I'm trying to make a general method for sending SOAP requests and getting responses. I'm programming using Groovy and I'm using the wslite library to help me out with SOAP. Here's a sample snippet for making a SOAP request and getting a response:
#Grab('com.github.groovy-wslite:groovy-wslite:1.1.2')
import wslite.soap.*
SOAPClient client = new SOAPClient('http://www.dneonline.com/calculator.asmx')
def response = client.send(SOAPAction: 'http://tempuri.org/Add') {
body {
Add(xmlns: 'http://tempuri.org/') {
intA(x)
intB(y)
}
}
}
By general, I meant being able to dynamically create a SOAP request (given certain information such as the service/method name, the parameters contained in the method, etc.) and obtain the SOAP response. I'm thinking something like this:
#Grab('com.github.groovy-wslite:groovy-wslite:1.1.2')
import wslite.soap.*
def getResponse(String clientURL, String action, String service, String serviceNamespace, Map parameters, ...) {
SOAPClient client = new SOAPClient(clientURL)
def response = client.send(SOAPAction: action) {
body {
"$service"(xmlns: serviceNameSpace) {
...
}
}
}
}
My problem lies in constructing the closure for the request body. Like, in example, if my method received a service Add, a serviceNamespace http://tempuri.org/, and a parameter map like so: [intA: x, intB: y]... how do I merge all of these so that I can construct this kind of closure:
Add(xmlns: 'http://tempuri.org/') {
intA(x)
intB(y)
}
I'm pretty much a newbie to Groovy, so don't be too harsh. If there's a better way to implement this concept of a general method, I would gladly like to hear it. The concept is similar to this. But I'd rather play with Map than a String. I'm not using Grails, really. Just plain Groovy.
In short, cfrick is correct:
[intA: x, intB: y].each{fn,arg -> delegate."$fn"(arg) }
How does it work?
An easy way to see how this works is to simulate it with a fake client class:
groovy.util.NodeBuilder
class Client {
def send(String action, Closure closure) {
closure.delegate = new NodeBuilder()
closure()
}
}
def client = new Client()
def response = client.send('http://tempuri.org/Add') {
body {
Add(xmlns: 'http://tempuri.org/') {
intA(1)
intB(2)
}
}
}
assert response.Add[0].#xmlns == 'http://tempuri.org/'
assert response.Add.intA.text() == '1'
assert response.Add.intB.text() == '2'
In the example above, the response object is created by Groovy's NodeBuilder. It's just a quick way to prototype something that processes the closure passed to Client.send().
With this testable code I'll try what cfrick suggested and validate that it works:
def doIt(String action, String service, String serviceNamespace, Map params) {
def client = new Client()
client.send(action) {
body {
"$service"(xmlns: serviceNamespace) {
params.each { method, argument ->
delegate."$method"(argument)
}
}
}
}
}
response = doIt('http://tempuri.org/Add', 'Add', 'http://tempuri.org/', [intA: 1, intB: 2])
assert response.Add[0].#xmlns == 'http://tempuri.org/'
assert response.Add.intA.text() == '1'
assert response.Add.intB.text() == '2'
Request Body
In addition, you can factor out the process of creating the request body:
def getRequestBody(String service, String serviceNamespace, Map params) {
{ ->
"$service"(xmlns: serviceNamespace) {
params.each { method, argument ->
delegate."$method"(argument)
}
}
}
}
def doIt(String action, String service, String serviceNamespace, Map params) {
def client = new Client()
client.send(action) {
body(getRequestBody(service, serviceNamespace, params))
}
}

Accessing session information inside a custom PartHandler in Play! Framework 2.0

In order to achieve a streaming upload I have written a custom PartHandler (Thread here ).
I now need to access a value that is stored inside the play! session inside the PartHandler.
How can I do that ?
Code sample:
def uploadFile() =
Action( parse.multipartFormData(myPartHandler) )
{ request =>
request.session.get("myValue") // <-- Recovering value is fine here
Ok("Done") }
def myPartHandler: BodyParsers.parse.Multipart.PartHandler[MultipartFormData.FilePart[Result]] = {
parse.Multipart.handleFilePart {
case parse.Multipart.FileInfo(partName, filename, contentType) =>
// ** Need to access a value in session here **
//request.session.get("myValue")...
// Handle part ...
Thanks!
With the help of other users of the play! framework google group, here is how to access the request inside a custom partHandler.
//Create a body parser
val myBodyParser = BodyParser { request =>
parse.multipartFormData(myPartHandler(request)).apply(request)
}
def uploadFile() = Action(myBodyParser)
{request =>Ok("Done")}
def myPartHandler(request: RequestHeader) : BodyParsers.parse.Multipart.PartHandler[MultipartFormData.FilePart[Result]] = {
parse.Multipart.handleFilePart {
case parse.Multipart.FileInfo(partName, filename, contentType) =>
println(request.session.get("myValueKey"));

Grails validation error from service method

I have a method in a service class that creates an object:
def createContent (fileName, description) {
def content = new Content(
fileName:fileName,
description:description,
).save()
}
Neither of those properties are nullable. How can I pass the validation errors back to be displayed? I've tried flash.message and render, both of which don't work from within service classes. I also tried
.save(failOnError:true)
which displayed a long list of errors.
Simplifying everything it should look like this.
Service method:
def createContent (fileName, description) {
//creating an object to save
def content = new Content(
fileName:fileName,
description:description,
)
//saving the object
//if saved then savedContent is saved domain with generated id
//if not saved then savedContent is null and content has validation information inside
def savedContent = content.save()
if (savedContent != null) {
return savedContent
} else {
return content
}
}
Now in controller:
def someAction = {
...
def content = someService.createContent (fileName, description)
if (content.hasErrors()) {
//not saved
//render create page once again and use content object to render errors
render(view:'someAction', model:[content:content])
} else {
//saved
//redirect to show page or something
redirect(action:'show', model:[id:content.id])
}
}
And someAction.gsp:
<g:hasErrors bean="${content}">
<g:renderErrors bean="${content}" as="list" />
</g:hasErrors>
And in general you should look through this: Grails validation doc

GridGain / Scala - Generate Jobs within existing Job

As a proof of concept, I'm building this extremely simple Twitter Friends crawler. Here's what it will do:
Execute CrawlJob for Twitter account "twitter-user-1"
Find all friends of "twitter-user-1"
Execute CrawlJob for all friends of "twitter-user-1"
Here's what my code looks like so far:
def main( args:Array[String] ) {
scalar {
grid.execute(classOf[CrawlTask], "twitter-user-1").get
}
}
class CrawlTask extends GridTaskNoReduceSplitAdapter[String] {
def split( gridSize:Int, arg:String): Collection[GridJob] = {
val jobs:Collection[GridJob] = new ArrayList[GridJob]()
val initialCrawlJob = new CrawlJob()
initialCrawlJob.twitterId = arg
jobs.add(initialCrawlJob)
jobs
}
}
class CrawlJob extends GridJob {
var twitterId:String = new String()
def cancel() = {
println("cancel - " + twitterId)
}
def execute():Object = {
println("fetch friends for - " + twitterId)
// Fetch and execute CrawlJobs for all friends
return null
}
}
I have Java services prepared for all twitter interaction. Need some examples to figure out how to create new jobs within an existing job and associate it with the original Task.
Thanks | Srirangan
How did I get around this?
Conceptually unite GridTasks and GridJobs. MySpecialGridTask can only have one MySpecialGridJob.
Then, it is easy to execute new GridTasks in the Task or the Job.
In the example above:
class CrawlJob extends GridJob {
var twitterId:String = new String()
def cancel() = {
println("cancel - " + twitterId)
}
def execute():Object = {
println("fetch friends for - " + twitterId)
// Fetch and execute CrawlJobs for all friends
// Execute Job Here
grid.execute(classOf[CrawlTask], "twitter-user-2").get
grid.execute(classOf[CrawlTask], "twitter-user-3").get
return null
}
}