How to send an array of a complex object with GroovyWS - soap

I'm about to call a webservice created in C#, that takes a parameter
KmlSystemVariable[] sysVariables
How can I pass a parameter like that using GroovyWS? It doesn't need to have any values, could be an empty array.
Looks like the full class name is Consorte.Pulse.Data.KmlSystemVariable
I enabled logging as described in GroovyWS and complex requests to get the namespace for KmlSystemVariable, and it looks like I can create a KmlSystemVariable with:
proxy.create("org.datacontract.schemas._2004._07.consorte_pulse.KmlSystemVariable")
But how do I create an array of KmlSystemVariable?

It should be enough to just wrap your proxied objects into a Groovy list and use it as the parameter. GroovyWS will do the transformation from List to SOAP array for you behind the scenes.
Example:
def ksv1 = proxy.create("org.datacontract.schemas._2004._07.consorte_pulse.KmlSystemVariable")
def ksv2 = ...
def ksv3 = ...
def list = [ksv1, ksv2, ksv3]
proxy.<some ws method>(list)

Related

Play Framework request attributes with typed key

I seem to have issues accessing the attributes of the request attributes map in Play. Following the explanation offered by Play (Link), I should get the correct data from the attributes, but the Option is returned as None.
My structure is as follows. One controller (later injected named as "sec") has the typed attribute for shared access to it:
val AuthenticatedAsAttr: TypedKey[AuthenticatedEmail] = TypedKey("AuthenticatedAs")
The type AuthenticatedEmail is defined in the companion object of this controller as a case class:
case class AuthenticatedEmail(email: String)
The filter passes the attribute to the next request:
val attrs = requestHeader.attrs + TypedEntry[AuthenticatedEmail](sec.AuthenticatedAsAttr, AuthenticatedEmail(email))
nextFilter(requestHeader.withAttrs(attrs))
When trying to then access this attribute in another controller, the returned Option is None:
val auth = request.attrs.get(sec.AuthenticatedAsAttr)
I confirmed via println that the value is definitely in request.attrs but run out of options to debug the issue successfully. A fraction of the println output below.
(Request attrs,{HandlerDef -> HandlerDef(sun.misc .... ,POST, ... Cookies -> Container<Cookies(Cookie ... , AuthenticatedAs -> AuthenticatedEmail(a#test.de), ... })
My Scala version is 2.12.6, Play Framework version 2.6.18. Any help is highly appreciated.
It turns out that the TypedKey must be within an object, not an inject-able controller. So moving it to an object like the following resolves the issue:
object Attrs {
val AuthenticatedAsAttr: TypedKey[AuthenticatedEmail] = TypedKey("AuthenticatedAs")
}
The reason is the implementation of TypedKey (Link), which does not contain an equals method and therefore reverts to comparing memory references.

Have a List in Play framework web service parameters

I have written this web service in play framework.
controller
def getByGenre(genre: String) = Action {
val result = Await.result(Movies.getByGenre(genre), 5 seconds)
Ok(toJson(result))
}
routes
GET /movies/genre/:genre controllers.MoviesController.getByGenre(genre: String)
However a user may select multiple Genre. Therefore I need to convert the genre parameter to a List[String]
I also need to know how to pass that Array parameter to the web service using CURL.
If you can pass the genres parameter as part of the query string, just repeat the parameter with different values and then retrieve it like this:
def getByGenre() = Action.async { implicit request =>
val genres = request.queryString.get("genres")
Movies.getByGenre(genres).map { movies =>
Ok(toJson(movies))
}
}
Your route will be:
GET /movies/genre controllers.MoviesController.getByGenre()
Also, notice that you will need to change the Movies.getByGenre signature to:
def getByGenre(genres: Option[Seq[String]]): Seq[Movies]
An final url will be something like #mfirry showed:
myhost.com/movies/genre?genre=action&genre=drama
Finally, as you may have noticed, I've removed the blocking code from you action. Using Await at your controller means that you action would be blocking for at least 5 seconds at the worst case scenario. I suggest you to take a look at the following page of Play docs:
https://www.playframework.com/documentation/2.5.x/ScalaAsync

Setting the property of an object using a variable value in scala

I'm trying to create a restful method to update data in the database, I'm using Scala on Play! framework. I have a model called Application, and I want to be able to update an application in the database. So the put request only requires the id of the application you want to update, then the optional properties you want to update.
So in my routes I have this:
PUT /v1/auth/application controllers.Auth.update_application(id: Long)
The method I currently have is this:
def update_application(id: Long) = Action { implicit request =>
var app = Application.find(id)
for((key, value) <- request.queryString) {
app."$key" = value(0)
//app.name = value(0)
}
val update = Application.update(id, app)
Ok(generate(
Map(
"status" -> "success",
"data" -> update
)
)).as("application/json")
}
In the method above I am looping through the request and the app object as a map instance, then updating the app model to be updated using the model. I know there is an easier way is to create the request string as map and just iterate through the object, but I am doing it this way for learning purposes. I'm new to Play! and Scala, barely a week new.
Is there a way to set a property using a variable dynamically that way? In the above method at the end of the loop that is how I would update a object's property in Groovy. So I'm looking for the equivalent in Scala. If Scala can't do this, what is the best way about going about accomplishing this task? Reflection? I don't want to over-complicate things
Play! provides play.api.data.Forms which allows creating a Form that uses the apply() and unapply() methods of a case class. Then you can call form.fill(app) to create a form with the initial state, bindFromRequest(request) to update the form with the request parameters, and get() to obtain a new instance with updated fields.
Define the form only once:
val appForm = Form(
mapping(
"field1" -> text,
"field2" -> number
)(Application.apply)(Application.unapply)
)
Then in your controller:
val app = appForm.fill(Application.find(id)).bindFromRequest(request).get
val update = Application.update(id, app)
Check out Constructing complex objects from the documentation.

Cannot access the parameter of a Menu.param from a Lift Snippet

I'm trying to extract the parameter from a Lift Menu.param within a snippet so that I can use it to create a named Comet. However, I get a NullPointerException when I try to pass the parameter to the snippet using SnippetDisptach in my Boot.scala, as suggested here:
http://comments.gmane.org/gmane.comp.web.lift/44299
I've created the Menu item as follows:
object AnItemPage {
// create a parameterized page
def menu = Menu.param[Item]("Item", "Item",
s => fetchItem(s), item => item._id.toString) / "item"
private def fetchItem(s:String) : Box[Item] = synchronized {
ItemDAO.findById(ObjectId.massageToObjectId(s))
}
}
I've added the menu to SiteMap. I've also created a Snippet which I would like to pick up the Item parameter. (I'm using fmpwizard's InsertNamedComet library here):
class AddCometItemPage(boxedItem: Box[Item]) extends InsertNamedComet with DispatchSnippet{
val item : Item = boxedItem.openOr(null)
override lazy val name= "comet_item_" + item._id.toString
override lazy val cometClass= "UserItemCometActor"
def dispatch = null
}
My next step is to crate an instance of this class as demonstrated by David Pollak here:
http://comments.gmane.org/gmane.comp.web.lift/44299
This is what I have added to my Boot.scala:
LiftRules.snippetDispatch.append {
case "item_page" => new AddCometItemPage(AnItemPage.menu.currentValue)
}
My item.html references this snippet:
<div class="lift:item_page">
I get the following null pointer exception when I compile and run this:
Exception occurred while processing /item/5114eb4044ae953cf863b786
Message: java.lang.NullPointerException
net.liftweb.sitemap.Loc$class.siteMap(Loc.scala:147)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.siteMap(Menu.scala:170)
net.liftweb.sitemap.Loc$class.allParams(Loc.scala:123)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.allParams(Menu.scala:170)
net.liftweb.sitemap.Loc$class.net$liftweb$sitemap$Loc$$staticValue(Loc.scala:87)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.net$liftweb$sitemap$Loc$$staticValue(Menu.scala:170)
net.liftweb.sitemap.Loc$$anonfun$paramValue$2.apply(Loc.scala:85)
net.liftweb.sitemap.Loc$$anonfun$paramValue$2.apply(Loc.scala:85)
net.liftweb.common.EmptyBox.or(Box.scala:646)
net.liftweb.sitemap.Loc$class.paramValue(Loc.scala:85)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.paramValue(Menu.scala:170)
net.liftweb.sitemap.Loc$$anonfun$currentValue$3.apply(Loc.scala:114)
net.liftweb.sitemap.Loc$$anonfun$currentValue$3.apply(Loc.scala:114)
net.liftweb.common.EmptyBox.or(Box.scala:646)
net.liftweb.sitemap.Loc$class.currentValue(Loc.scala:114)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.currentValue(Menu.scala:170)
bootstrap.liftweb.Boot$$anonfun$lift$8.apply(Boot.scala:107)
bootstrap.liftweb.Boot$$anonfun$lift$8.apply(Boot.scala:106)
net.liftweb.util.NamedPF$$anonfun$applyBox$1.apply(NamedPartialFunction.scala:97)
net.liftweb.util.NamedPF$$anonfun$applyBox$1.apply(NamedPartialFunction.scala:97)
net.liftweb.common.Full.map(Box.scala:553)
net.liftweb.util.NamedPF$.applyBox(NamedPartialFunction.scala:97)
net.liftweb.http.LiftRules.snippet(LiftRules.scala:711)
net.liftweb.http.LiftSession$$anonfun$net$liftweb$http$LiftSession$$findSnippetInstance$1.apply(LiftSession.scala:1506)
net.liftweb.http.LiftSession$$anonfun$net$liftweb$http$LiftSession$$findSnippetInstance$1.apply(LiftSession.scala:1506)
net.liftweb.common.EmptyBox.or(Box.scala:646)
net.liftweb.http.LiftSession.net$liftweb$http$LiftSession$$findSnippetInstance(LiftSession.scala:1505)
net.liftweb.http.LiftSession$$anonfun$locateAndCacheSnippet$1$1$$anonfun$apply$88.apply(LiftSession.scala:1670)
net.liftweb.http.LiftSession$$anonfun$locateAndCacheSnippet$1$1$$anonfun$apply$88.apply(LiftSession.scala:1669)
Has anybody any idea where I'm going wrong? I've not been able to find a lot of information on Menu.param.
Thank you very much for your help.
f
I have never tried what you are doing, so I am not sure the best way to accomplish it. The way you are using the Loc Param, you are extracting a variable from a URL pattern. In your case, http://server/item/ITEMID where ITEMID is the string representation of an Item, and which is the value that gets passed to the fetchItem function. The function call will not have a value if you just arbitrarily call it, and from what I can see you are requesting a value that is not initialized.
I would think there are two possible solutions. The first would be to use S.location instead of AnItemPage.menu.currentValue. It will return a Box[Loc[Any]] representing the Loc that is currently being accessed (with the parameters set). You can use that Loc to retrive currentValue and set your parameter.
The other option would be to instantiate the actor in your snippet. Something like this:
item.html
<div data-lift="AnItemPage">
<div id="mycomet"></div>
</div>
And then in your AnItemPage snippet, something like this:
class AnItemPage(item: Item) {
def render = "#mycomet" #> new AddCometItemPage(item).render
}
I haven't tested either of those, so they'll probably need some tweaking. Hopefully it will give you a general idea.

Is there a generic way of setting field values in mapper from list of values?

Is there a way of creating method for setting the value in the Model's fields without setting the values explicitly like -
ModelName.create.fieldName1("value").fieldName2("value2") and so on
Can we iterate through all available fields of that model and set their values form some list-of-values ?
something like ...
Model.allFields.foreach((fld)=> {
fld.set(valueList(indx)); indx+=1
}
Actually I want to set values into all models using some generic method that works for all models.
According to my comment:
val list = List(...)
val record = YourRecordClass.createRecord
record.allFields.zip(list).foreach {case(field,value) => field.setFromAny(value)}