Play Framework Multi-Tenant Filter - java

I'm attempting to build a multi-tenant application using Play Framework 2.2 and have run into a problem. I want to set a session key in the global onRouteRequest (or onRequest in Java) that identifies the site ID for the domain the user is requesting. In literally dozens of other frameworks this type of thing is painless (e.g. Django), but I'm learning that the session object in Play is apparently immutable, however.
So, right now, I have something like this:
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
if (request.session.get("site").isEmpty){
val id = models.Site.getSiteUIDFromURL(request.host.toLowerCase()).toString()
if (!id.isEmpty){
//what goes here to set the session?
}else{
//not found - redirect to a general notFound page
}
}
super.onRouteRequest(request)
}
And, although it's not the most efficient way using a database lookup, it works for testing right now. I need to be able to set a session key in the global but am completely lost on how to do that. If there are any better methods I am all ears (perhaps wrapping my controllers?).
I'm open to solution examples in either Java or Scala.

Think of actions in Play as being function calls, the input is the request, the output is the result. If you want to change the result of a wrapped function call, then you must first invoke the function, and then apply your change. Adding a key to a session is changing the result, since the session is sent to the client in the session cookie. In the code above, you're trying to do the change before you have a result to change, ie, before you call super.onRouteRequest.
If you don't need to modify routing at all, then don't do this in onRouteRequest, do it in a filter, much easier there. But assuming you do need to modify routing, then you need to apply a filter to handler returned. This is what it might look like:
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
val maybeSite: Option[String] = request.session.get("site").orElse {
// Let's just assume that getSiteUIDFromUrl returns Option[String], always use Option if you're returning values that might not exist.
models.Site.getSiteUIDFromURL(request.host.toLowerCase())
}
maybeSite.flatMap { site =>
super.onRouteRequest(request).map {
case e: EssentialAction => EssentialAction { req =>
e(req).map(_.withSession("site" -> site))
}
case other => other
}
}
}
Check the source code for the CSRFFilter to see examples of how to add things to the session in a filter.

Related

How to get the current substate and the parent state out of the Spring Statemachine?

I am running a hierachical Spring Statemachine and - after walking through the inital transitions into state UP with the default substate STOPPED - want to use statemachine.getState(). Trouble is, it gives me only the parent state UP, and I cannot find an obvious way to retrieve both the parent state and the sub state.
The machine has states constructed like so:
StateMachineBuilder.Builder<ToolStates, ToolEvents> builder = StateMachineBuilder.builder();
builder.configureStates()
.withStates()
.initial(ToolStates.UP)
.state(ToolStates.UP, new ToolUpEventAction(), null)
.state(ToolStates.DOWN
.and()
.withStates()
.parent(ToolStates.UP)
.initial(ToolStates.STOPPED)
.state(ToolStates.STOPPED,new ToolStoppedEventAction(), null )
.state(ToolStates.IDLE)
.state(ToolStates.PROCESSING,
new ToolBeginProcessingPartAction(),
new ToolDoneProcessingPartAction());
...
builder.build();
ToolStates and ToolEvents are just enums. In the client class, after running the builder code above, the statemachine is started with statemachine.start(); When I subsequently call statemachine.getState().getId(); it gives me UP. No events sent to statemachine before that call.
I have been up and down the Spring statemachine docs and examples. I know from debugging that the entry actions of both states UP and STOPPED have been invoked, so I am assuming they are both "active" and would want to have both states presented when querying the statemachine. Is there a clean way to achieve this ? I want to avoid storing the substate somewhere from inside the Action classes, since I believe I have delegated all state management issues to the freakin Statemachine in the first place and I would rather like to learn how to use its API for this purpose.
Hopefully this is something embarrasingly obvious...
Any advice most welcome!
The documentation describes getStates():
https://docs.spring.io/spring-statemachine/docs/current/api/org/springframework/statemachine/state/State.html
java.util.Collection<State<S,E>> getStates()
Gets all possible states this state knows about including itself and substates.
stateMachine.getState().getStates();
to wrap it up after SMA's most helpful advice: turns out the stateMachine.getState().getStates(); does in my case return a list of four elements:
a StateMachineState instance containing UP and STOPPED
three ObjectState instances containing IDLE, STOPPED and PROCESSING,
respectively.
this leads me to go forward for the time being with the following solution:
public List<ToolStates> getStates() {
List<ToolStates> result = new ArrayList<>();
Collection<State<ToolStates, ToolEvents>> states = this.stateMachine.getState().getStates();
Iterator<State<ToolStates, ToolEvents>> iter = states.iterator();
while (iter.hasNext()) {
State<ToolStates, ToolEvents> candidate = iter.next();
if (!candidate.isSimple()) {
Collection<ToolStates> ids = candidate.getIds();
Iterator<ToolStates> i = ids.iterator();
while (i.hasNext()) {
result.add(i.next());
}
}
}
return result;
}
This maybe would be more elegant with some streaming and filtering, but does the trick for now. I don't like it much, though. It's a lot of error-prone logic and I'll have to see if it holds in the future - I wonder why there isn't a function in the Spring Statemachine that gives me a list of the enum values of all the currently active states, rather than giving me everything possible and forcing me to poke around in it with external logic...

Scala with Spray Routing - accessing GET parameters?

I'm currently working on an application built in Scala with Spray routing.
So for dealing with a JSON document sent over POST, it's pretty easy to access the variables within the body, as follows;
respondWithMediaType(`application/json`) {
entity(as[String]) { body =>
val msg = (parse(body) \ "msg").extract[String]
val url = (parse(body) \ "url").extractOpt[String]
However, I'm now trying to write an additional query with GET, and am having some issues accessing the parameters sent through with the query.
So, I'm opening with;
get {
respondWithMediaType(`application/json`) {
parameterSeq { params =>
var paramsList = params.toList
So, this works well enough in that I can access the GET params in a sequential order (just by accessing the index) - the problem is, unfortunately I don't think we can expect GET params to always be sent in the correct order.
The list itself prints out in the following format;
List((msg,this is a link to google), (url,http://google.com), (userid,13))
Is there any simple way to access these params? For example, something along the lines of;
var message = paramsList['msg']
println(message) //returns "this is a link to google"
Or am I going about this completely wrong?
Apologies if this is a stupid question - I've only switched over to Scala very recently, and am still getting both acquainted with that, and re-acquainted with Java.
What I usually do is use the parameters directive to parse the data out to a case class which contains all the relevant data:
case class MyParams(msg: String, url: String, userId: Int)
parameters(
"msg".as[String],
"url".as[String],
"userId".as[Int]
).as[MyParams] {
myParams =>
// Here you have the case class containing all the data, already parsed.
}
To build your routes you could use the parameters directives. I'm not sure if this is what you're looking for, anyway you could use them as:
get {
parameters('msg) { (msg) =>
complete(s"The message is '$msg'")
}
}
Spray directives can be easily composed so you can use combine them in any way you want.
I hope that helps you.

PeopleSoft Component Interfaces: Create Method Doesn't Persist The New Object

I'm working with the PSJOA library. I have a Java app, and I'm testing each of the standard operations using the CI_PERSONAL_DATA. Everything works fine with the Get, Find and Save. But not with the Create, even though when I invoke the method, I get an OK response, with no apparent errors. The input parameter I'm sending (taken from the CreateKeys) is the KEYPROP_EMPLID.
The odd thing here is that, if instead I call the Create method using Web Services (through SoapUI), the new instances is correctly created. However, in this scenario, passing just the primary key KEYPROP_EMPLID is not enough and I have to fill more fields (as it I was performing an update).
Can someone point to me what might be happening? Is there some missing data? Maybe I misunderstood the creation behavior?
Thanks.
What exactly goes awry when you call create? That will create a new entry in the personal data component in PeopleSoft for the person with the supplied emplid. It will be editable, so you can fill in other information, but it will not persist until/unless you call save() afterwards.
Does the emplid already exist in the personal data component? If so, you should be calling get() instead.
Does the emplid already exist in the peoplesoft instance? If not, you should make sure it is in the system prior to using it.
Regarding the lack of error behavior, I have found the peoplesoft component interface APIs for java are notoriously unreliable. You can test them in real time through Application Designer (Via the "Test Component Interface" option in the drop-down menu), which I often find helpful.
Finally, calling session.checkMessages() on your session after performing a method on a CI can often generate error messages that otherwise will not be displayed.
EDIT: Here is a snippet of how we typically call/use it in our PeopleSoft HR instance:
ICiPersonalData wh = (ICiPersonalData)ses.getComponent("CI_PERSONAL_DATA");
if (wh == null) throw new UpdateException("Failed to get component");
wh.setInteractiveMode(true);
wh.setGetHistoryItems(true);
wh.setEditHistoryItems(true);
wh.setKeypropEmplid(emplid);
if (!existsInHR(emplid)) { // Direct database check
LOG.debug("Creating a new HR person.");
if ( ! wh.create() )
LOG.warn("wh.create returned false for emplid ="+emplid);
ses.checkMessages(); // will throw exception if errors exist
wh.setPropDerivedEmp("Y");
rs.put("NEW","Y");
setKeyPersonalData(wh, emplid, rs); // Sets name, etc.
} else {
if (!wh.get())
LOG.warn("wh.get returned false for emplid ="+emplid);
ses.checkMessages();
}

Upsert for LDAP directory in Java

I'm attempting to execute an Upsert using the Novell JLDAP library, unfortunately, I'm having trouble finding an example of this. Currently, I have to:
public EObject put(EObject eObject){
Subject s = (Subject) eObject;
//Query and grab attributes from subject
LDAPAttributes attr = resultsToAttributes(getLDAPConnection().get(s));
//No modification needed - return
if(s.getAttributes().equals(attr)){
return eObject;
} else {
//Keys:
//REPLACE,ADD,DELETE, depending on which attributes are present in the maps, I choose the operation which will be used
Map<String,LDAPAttribute> operationalMap = figureOutWhichAttributesArePresent(c.getAttributes(),attr);
//Add the Modifcations to a modification array
ArrayList<LDAPModification> modList = new ArrayList<LDAPModification>();
for(Entry entry: operationalMap.getEntrySet()){
//Specify whether it is an update, delete, or insert here. (entry.getKey());
modList.add(new LDAPModification(entry.getKey(),entry.getValue());
}
//commit
connection.modify("directorypathhere",modList.toArray(new LDAPModification[modList.size()]));
}
I'd prefer to not have to query on the customer first, which results in cycling through the subject's attributes as well. Is anyone aware if JNDI or another library is able to execute an update/insert without running multiple statements against LDAP?
Petesh was correct - the abstraction was implemented within the Novell library (as well as the UnboundId library). I was able to "upsert" values using the Modify.REPLACE param for every attribute that came in, passing in null for empty values. This effectively created, updated, and deleted the attributes without having to parse them first.
In LDAP, via LDIF files, an upset would be a single event with two steps. A remove and add of a value. This is denoted by a single dash on a line, between the remove then the add.
I am not sure how you would do it in this library. I would would try to modList.remove and then modList.add one after another and see if that works.

Redirect with anchor in play 2

I'm looking for possibility to add anchor to url returned in controller:
public static Result open(String id) {
// here I want to add acnhor like #foo to the produced url
return redirect(routes.MyPage.show(id));
}
I found that it was possible in play 1 using addRef method, but I couldn't find any replacement of the method in play 2.
Of course I can use concatenation like:
public static Result open(String id) {
// here I want to add acnhor like #foo to the produced url
return redirect(routes.MyPage.show(id).url + "#foo");
}
But it seems ugly.
Thank you for any help! Have a good day!
Before trying to answer that question.
I should recommend you change whatever behavior you're currently setting.
Because, an URL fragment's purpose is client side only. Such fragment is never sent to the server, so that it's cumbersome to do the opposite.
However, here is the embryo of a (quite?) elegant solution that you could follow.
What I'll try to do is to leave the browser deal with the fragment, in order to keep potential behaviors (f.i. go to ID or even deal with history...).
To do so, you could add an implicit parameter to your main template which will define the fragment that the URL should have:
#(title: String)(content: Html)(urlFragment:Option[UrlFragment] = None)
As you can see I wrapped the parameter in an Option and default'ed it to None (in order to avoid AMAP pollution).
Also, it simply wraps a String but you could use String alone -- using a dedicated type will enforce the semantic. Here is the definition:
case class UrlFragment(hash:String)
Very simple.
Now here is how to tell the browser to deal with it. Right before the end of the head element, and the start of body, just add the following:
#urlFragment.map { f =>
<script>
$(function() {
//after everything is ready, so that other mechanism will be able to use the change hash event...
document.location.hash = "#Html(#f.hash)";
});
</script>
}
As you can see, using map (that is when the urlFragment is not None) we add a script block that will set the hash available in urlFragment.
This might be a start, however... Think about another solution for the whole scenario.
As of Play 2.4, it's possible to use Call.withFragment().
routes.Application.index.withFragment("some-id").absoluteURL(request)
This was added by PR #4152.

Categories