How can I get the body of an action as string - scala

I have two actions. The first serves single assets and the second should serve all the single assets combined into one asset. So my idea was to call the first action which serves the single assets from the second action which serves the combined asset. Some of you will say this is a bad idea, because I could load the assets directly from file system and combine them. But this isn't possible, because the first action is chained with other actions to do some additional operations(Fingerprinting, ...) on a asset.
So here are my actions:
The first serves a single asset. In this implementation it calls only the next action in the chain.
abstract override def at(path: String, file: String): Action[AnyContent] = {
super.at(path, file)
}
The second accepts a list of files as JSON. Then it iterates over the list and calls the first action with a single file.
def consolidate = Action(parse.json) { request =>
val files = request.body.as[List[String]]
for (file <- files) {
val action = at(path, new URL(file).getPath.substring(1))
val result = action.apply(request)
}
Ok()
}
Now my problem is, how can I get the asset as string? The variable result contains a Iteratee[Array[Byte], Result]. How can I extract the asset data from it?
The play.api.test.Helper object contains a contentAsString and a contentAsBytes method. But this doesn't help me further!

The Iteratee represents the consumer side of the action. There is no documentation for the method returning the Iteratee but I'm guessing it will be used to consume the input stream of data from the client during a request. So, in short, it won't help you here.
You could take the code from the first action, the one you need to invoke in consolidate and factor it out into some method, and use that method in both actions. Is that feasible for you ?

Related

Repopulating form fields in Play Framework

Using the Play Framework (2.6) documentation; I am attempting to handle form submission. But I'm running into an issue in repopulating the form fields - which is what I want to do if it has errors (so users can edit their entry rather than having to re-enter).
newForm.bindFromRequest.fold(
errorForm => {
BadRequest(views.html.form(errorForm))
},
formData => {
val oWriteJso = Json.toJsObject(formData) match {
case x if(x.fields.nonEmpty) => getCreatedFieldValues(x)
case _ => None
}
val oRes = Redirect(routes.Application.index).flashing("success" -> "Entry saved!")
apiC.writeAndRedirect("c", collName, None, oWriteJso)(oRes)(request)
}
)
My issue is that the example in the documentation only shows how to pass errorForm directly to a form template (e.g. views.html.form) rather than being able to render the whole page again (i.e. using views.html.index or a Redirect) with the input form fields being populated from the previous request. I found this answer as the closest to this issue but it is a little old and I am using Scala so wasn't able to implement it. Just have no idea how anyone else is doing this or what the sensible, standard approach is. Thanks for any light on this_
If you use the Play helper functions for generating input tags in your view file. They should populate with your values from the last request.
For example you can create an HTML form in your view file using helper methods like this:
#helper.form(action = routes.Application.userPost()) {
#helper.inputText(userForm("name"))
#helper.inputText(userForm("age"))
}
You can take a look at Play documentation about helpers in view files at the following link:
https://www.playframework.com/documentation/2.7.x/ScalaForms#Showing-forms-in-a-view-template

How to use delta trigger in flink?

I want to use the deltatrigger in apache flink (flink 1.3) but I have some trouble with this code :
.trigger(DeltaTrigger.of(100, new DeltaFunction[uniqStruct] {
override def getDelta(oldFp: uniqStruct, newFp: uniqStruct): Double = newFp.time - oldFp.time
}, TypeInformation[uniqStruct]))
And I have this error:
error: object org.apache.flink.api.common.typeinfo.TypeInformation is not a value [ERROR] }, TypeInformation[uniqStruct]))
I don't understand why DeltaTrigger need TypeSerializer[T]
and I don't know what to do to remove this error.
Thanks a lot everyone.
I would read into this a bit https://ci.apache.org/projects/flink/flink-docs-release-1.2/dev/types_serialization.html sounds like you can create a serializer using typeInfo.createSerializer(config) on your type info. Note what you're passing in currently is a type itself and NOT the type info which is why you're getting the error you are.
You would need to do something more like
val uniqStructTypeInfo: TypeInformation[uniqStruct] = createTypeInformation[uniqStruct]
val uniqStrictTypeSerializer = typeInfo.createSerializer(config)
To quote the page above regarding the config param you need to pass to create serializer
The config parameter is of type ExecutionConfig and holds the
information about the program’s registered custom serializers. Where
ever possibly, try to pass the programs proper ExecutionConfig. You
can usually obtain it from DataStream or DataSet via calling
getExecutionConfig(). Inside functions (like MapFunction), you can get
it by making the function a Rich Function and calling
getRuntimeContext().getExecutionConfig().
DeltaTrigger needs a TypeSerializer because it uses Flink's managed state mechanism to store each element for later comparison with the next one (it just keeps one element, the last one, which is updated as new elements arrive).
You will find an example (in Java) here.
But if all you need is a window that triggers every 100msec, then it'll be easier to just use a TimeWindow, such as
input
.keyBy(<key selector>)
.timeWindow(Time.milliseconds(100)))
.apply(<window function>)
Updated:
To have hour-long windows that trigger every 100msec, you could use sliding windows. However, you would have 10 * 60 * 60 windows, and every event would be placed into each of these 36000 windows. So that's not a great idea.
If you use a GlobalWindow with a DeltaTrigger, then the window will be triggered only when events are more than 100msec apart, which isn't what you've said you want.
I suggest you look at ProcessFunction. It should be straightforward to get what you want that way.

Notification between classes using Observable

I have a class with a list of users from a server.
Other classes can manipulate the list on the server e.g. call add or delete operation.
My Core-Class has a reference to the other classes which are manipulating the list on the server.
I would like to:
Make a init call in Core-Class to get the list on the beginning
The Core-Class will be notified by plugins each time the list was manipulated on the server, so the Core-Class get the list from the server again.
Notify other classes that the list was reloaded and forward the new list.
My structure
Core {
users: [];
plugin1: Plugin;
plugin2: Plugin;
//Get a new list of users from the server
loadUsers() {
userService.loadUsers.then(function (res) {
this.users = res;
})
}
}
Plugin {
//sends a request to the server to create a special user,
//depending on plugin implementation
createUser();
}
I'm only just starting of using rx. I understand the factory methods, hot vs cold observable and other basic stuff. But i can not imagine how to do it with rx in the right way.
Thanks.
My idea of reactive implementation would be:
In your UserService add the following:
var loadSubject = new Subject();
var usersObservable = loadSubject.flatMap(
Observable.fromPromise(<your http call that returns promise>)).share()
function loadUsers(){
loadSubject.next(true);
}
Then each plugin that made changes will simply call:
userService.loadUsers();
Your Core, plugins, and other classes that would like to get updated will simply do:
loadService.usersObservable.subscribe(function(usersFreshValue){
this.users = usersFreshValue;
})
Note that I used the '.share()' to avoid duplication of the data.
Possible improvements:
Instead of the loadUsers method, have each plugin call userService.loadSubject.next(true);
Use backpressure/buffering operators to avoid too frequent calls. For example debounce (CAUTION! when used incorrectly, might lead to starvation) or bufferWithTime + filter (to ensure you don't trigger on empty buffers)
Use behavioral/replay observables so that new subscribers will quickly get the latest value.

Downloadable xml files in Play Framework

I am a Scala/PlayFramework noob here, so please be easy on me :).
I am trying to create an action (serving a GET request) so that when I enter the url in the browser, the browser should download the file. So far I have this:
def sepaCreditXml() = Action {
val data: SepaCreditTransfer = invoiceService.sepaCredit()
val content: HtmlFormat.Appendable = views.html.sepacredittransfer(data)
Ok(content)
}
What it does is basically show the XML in the browser (whereas I actually want it to download the file). Also, I have two problems with it:
I am not sure if using Play's templating "views.html..." is the best idea to create an XML template. Is it good/simple enough or should I use a different solution for this?
I have found Ok.sendFile in the Play's documentation. But it needs a java.io.File. I don't know how to create a File from HtmlFormat.Appendable. I would prefer to create a file in-memory, i.e. no new File("/tmp/temporary.xml").
EDIT: Here SepaCreditTransfer is a case class holding some data. Nothing special.
I think it's quite normal for browsers to visualize XML instead of downloading it. Have you tried to use the application/force-download content type header, like this?
def sepaCreditXml() = Action {
val data: SepaCreditTransfer = invoiceService.sepaCredit()
val content: HtmlFormat.Appendable = views.html.sepacredittransfer(data)
Ok(content).withHeaders("Content-Type" -> "application/force-download")
}

Managing Resources with FRP in Scala RX

I'm using scala rx for an application. I have a reactive variable holding a File (which is a PDF file). I'm using a library to render pages from this pdf file to the screen. Now the PDF library I'm using gives me an object (let's call it Doc), which I can use to render single pages. But in order to render a page from a Doc object, the Doc object must be opened (thus the resource must be acquired).
Right now I'm loading the pdf file for each page I'm rendering anew (creating a new Doc object and closing it after rendering the single page). This makes the rendering of the page functional (given a file and a page number, return an image).
Is there a way to cling to an opened resource and close it on change in FRP in general, and for scala rx in particular? How would one handle this very common situation?
You can simply enclose the Doc object. So instead of render being
def render(file: File, pageNumber: Int): Image = // blah blah blah
change it to:
def open(file: File): (Int => Image) = {
val doc = // call your library to read file
(x: Int) => doc.getPage(x)
}
and then pass the function open returns to whatever page change signal you're reacting to.
Edit: Oh, I see, so you're saying you want it to close the file whenever the file:File signal changes to be a different file. In that case you should be able do something like this:
def pageGetterRx(file: Rx[File]): Rx[Int => Image] = {
val doc: Var[Doc] = Var(null)
val o = file.foreach { f =>
Option(doc()).foreach(_.close)
doc() = PdfLib.read(f) // or however you do the reading
}
Rx {
(x: Int) => doc().getPage(x)
}
}
Edit 2: To clarify, if you impose a "assemble network of functions phase / run the network on some signal(s) phase" distinction on FRP, the above function would be called only once; in the assemble phase. To say it another way, pageGetterRx (a lousy name, I'm fully aware) doesn't participate in a FR way, instead it returns a signal of lambdas that each close over one particular file and return pages from it.