We are trying to implement some flow control in Play, kind of a wizard with several steps. What is the best practice to do it in Play?
Requirements we have:
Should allow multi-step flows, like step1 -> step2 -> step3 -> step4 -> finish
Should be able to change order or steps depending on context, so if user selects a checkbox on step2, flow should be step1 -> step2 -> warningStep -> step5 -> finish
Ideally needs support for "Back" button to return between steps
The problem we have is that any single step in flow doesn't know where it should redirect next and since Play session is very simple, it won't help here much.
Here is the solution we currently have:
Store Flow steps in database in user object with #OneToMany public List<FlowStep> flowSteps
Provide methods in user model to add/remove/skip and change order of flow steps stored for this user
Implement steps normally, with form action leading to "doStep3" controller etc
Implement "Flows" controller that uses #Before and #After interceptors to correctly redirect to next step after current step is processed and no validation errors found
Added Flows.next() controller that redirects to next step (used for "Skip" button href)
What are the disadvantages of this solution? Is there any better way (maybe some Play built-in methods) to improve it?
What you want is a finite state machine. To implement it, you'll need a class that knows all the possible transitions between steps. Then you can provide to it the current step and any relevant input, and it will return the output (where the output is the view to render next).
Then you use render to redirect the user, as in:
render("my/view/path.html", myparams);
This is not the only option, and storage of the transitions will depend on how complex you need them (can be hardcoded for simple scenarios, maybe stored in database for more complex ones), but it should work.
As Play is stateless you'll need to keep the information in the database (for complex scenarios where you need to take in account information for several steps) or, if the relevant togles are just a few, store them in the cookie itself.
I would avoid using #Before/#After as you are coupling the state machine to the controller. Ideally you want them to be idnependent, with the state machine returning only transitions that you can translate later into view paths. That will simplify changing transitions.
If the scenario is not extremely complex, I would not even bother to store them in the database. If you want it reusable and extremely flexible, then do it, otherwise it may be simpler to just "hardcode it".
Did you check this section in the Play documentation (a very quick read):
http://www.playframework.org/documentation/1.2.4/model#stateless
It lists the options you have for exactly what you are asking.
You can try to use Play Cache mechanism as pseudo session to store the validated steps instead of handling in the database. Using Play Cache would be a simpler solution
Related
What I mean by 'conditional' privileges is, for example: Say we have Event e. The user who CREATED Event e should be able to delete Event e and invite additional users to Event e, but only that user.
From tutorials I've seen, permissions and roles seem static, for example:
Doctor has a role doctor, with permissions x, y and z, but that is it...pretty static.
Is there a simple way to conditionally manage permissions with Spring Security?
Or would this be something better suited for the front-end? For example, the view would show a 'delete event' button only if the resource data for that particular Event confirms that the Event creator's ID is in fact the same ID stored in session memory/keychain/whatever for the currently logged in user, type of thing.
Thanks
First of all,
Or would this be something better suited for the front-end?
...show a 'delete event' button only if...
NO. Not as a reliable line of defence, no.
Well that probably depends on a tech stack, architecture etc, but as a rule of thumb, you shouldn't do it. I didn't write servlets/jsp, but I used spring security in a rich client (swing) application and even though we had all the control (I mean, we could guarantee that user cannot access some function no other way than clicking a button), we secured our models, not the gui.
You shouldn't be able to call Entity#delete no matter how you call it - via button click event or calling it directly in a test. In case of web application, imagine you don't display a button, but an attacker knows that button leads to example.com/entity?action=delete URL or something like that, he could access it directly even if you don't render the button.
With regard to the main question, spring security, roughly speaking, has two parts: RBAC and ACL. What you need seems to be the ACL part. Read some howtos and articles about domain security, it's a pretty complex stuff, but it can be suited for your needs for sure (with some effort, of course). What you described in a first paragraph may be achieved easily because every object has it's owner and it can be exploited.
Also, here's a good advice.
Edit: just to clear things up for future visitors. Point was: there should be some logic on the front-end, but it must not be the only security logic. Of course there's no need to clutter UI with buttons leading to functions you can't access.
In our Java app, using spring-aop, in order to collect certain statistics, we have two around-advices which get hit consecutively per request, like this: advice-A ->proceed-> advice-B ->proceed-> advice-B -> advice-A
To avoid writing to the DB twice, we want to share the information captured by the second advice with the first, and write it all to the DB after the proceed in the first (outer) advice.
How can this be done without using nasty things like static classes with ThreadLocals?
I read about perthis and pertarget, but if I understand it correctly that would only be useful if our service beans are request-scoped. Then you could wire one advice into the other and share information that way.
I have a lot of existing data in my database already, and want to develop a points mechanism that computes a score for each user based on what actions they do.
I am implementing this functionality in a pluggable way, so that it is independent of the main logic, and relies on Spring events being sent around, once an entity gets modified.
The problem is what to do with the existing data. I do not want to start collecting points from now, but rather include all the data until now.
What is the most practical way to do this? Should I design my plugins in such a way as to provide for an index() method, which will force my system to fetch every single entity from the database, send an EntityDirtyEvent, to fire the points plugins, for each one, and then update it, to let points get saved next to each entity. That could result in a lot of overhead, right?
The simplest thing would be to create a complex stored procedure, and then make the index() call that stored procedure. That however, seems to me like a bad thing either. Since I will have to write the logic for computing the points in java anyway, why have it once again in SQL? Also, in general I am not a fan of splitting business logic into the different layers.
Has anyone done this before? Please help.
First let's distinguish between the implementation strategy and business rules.
Since you already have the data, consider obtaining results directly from the data. This forms the data domain model. Design the data model to store all your data. Then, create a set of queries, views and stored procedures to access and update the data.
Once you have those views, use a data access library such as Spring JDBC Template to fetch this data and represent them into java objects (lists, maps, persons, point-tables etc).
What you have completed thus far does not change much, irrespective of what happens in the upper layers of the system. This is called Model.
Then, develop a rule base or logic implementation which determines, under what inputs, user actions, data conditions or for all other conditions, what data is needed. In mathetical sense, this is like a matrix. In programming sense, this would be a set of logic statements. If this and this and this is true, then get this data, else get that data, etc. This encompasses the logic in your system. Hence it is called "Controller".
Do not move this logic into the queries/stored procedure/views.
Then finally develop a front-end or "console" for this. In the simplest case, develop a console input system, which takes a .. and displays a set of results. This is your "view" of the system.
You can eventually develop the view into a web application. The above command-line view can still be viable in the form of a Restful API server.
I think there is one problem here to be considered: as I understand there's huge data in the Database so the idea to create only one mechanism to calculate the point system could not be the best approach.
In fact if you don't want to start collecting points but include all the data, you must process and calculate the information you have now. Yes, the first time you will run this can result an overhead, but as you said, you need this data calculated.
By other hand you may include another mechanism that attends changes in an entity and launches a different process capable of calculate the new pointing diffence that applies to this particular modification.
So, you can use one Service responsible of calculate the pointing system, one for a single entity and another, may be longer to finish, capable of calculate the global points. Even, if you don't need to be calculated in real-time you can create a scheduled job responsible of launch it.
Finally, I know it's not a good approach to split the business logic in two layers (Db + Java) but sometimes is a requirement do it, for example, if you need to reply quickly to a request that finally works with a lot of registries. I've found some cases that there's no other option than add business logic to the database (as a stored procedures, etc) to manage a lot of data and return the final result to the browser client (ex: calculation process in one specific time).
You seem to be heading in the right direction. You know you want your "points" thing decoupled from the main application. Since it is implied you are already using hibernate (by the tag!), you can tap into the hibernate event system (see here section 14.2). Depending upon the size/complexity of your system, you can plugin your points calculations here (if it is not a large/complex system), or you can publish your own event to be picked up by whatever software is listening.
The point in either design approach is that neither knows or cares about your point calculations. If you are, as I am guessing, trying to create a fairly general purpose plugin mechanism, then you publish your own events to that system from this tie-in point. Then if you have no plug-ins on a given install/setup, then no one gets/processes the events. If you have multiple plug-ins on another install/setup, then they each can decide what processing they need to do based upon the event received. In the case of the "points plugin" it would calculate it's point value and store it. No stored proc required....
You're trying to accomplish "bootstrapping." The approach you choose should depend on how complicated the point calculations are. If stored procedures or plain update statements are the simplest solution, do that.
If the calculations are complicated, write a batch job that loads your existing data, probably orders it oldest first, and fires the events corresponding to that data as if they've just happened. The code which deals with an event should be exactly the same code that will deal with a future event, so you won't have to write any additional code other than the batch jobs themselves.
Since you're only going to run this thing once, go with the simplest solution, even if it is quick and dirty.
There are two different ways.
One is you already know that - poll the database for for changed data. In that case you are hitting the database when there may not be change and it may slow down your process.
Second approach - Whenever change happens in database, the database will fire the event. That you can to using CDC (Change Data Capture). It will minimize the overhead.
You can look for more options in Spring Integration
I'm tinkering with Play! java framework and trying to understand MVC.
Consider this scenario: A blogging app has moderators and users, and both can update posts. Moderators' updates are immediately saved. Users' updates are queued to be approved by a moderator. In MVC, where do we put the logic to determine whether to update or queue the updates?
One way to do it is in the Controller (pseudo-code):
public void function update() {
User user = User.find("byEmail");
if ( user.isModerator() ) {
post.update( args );
}
else {
// save post in a temporary table where it awaits approval.
}
}
Am I right in using this approach or are there better alternatives?
I know that this is quite an old question, but I had the same - so this might be of help:
In my current project, the policy is to layer the authorisation checks. This way, the checks will be done where they fit best:
if it is important for consistancy of the data, checks are done in the model (very rare cases, needs to be set in the API documentation!).
most checks are done at controller level, so most checks are in a single place.
some checks are done in the "View" (this means they controll the JSON output of an API, and this in turn changes behaviour in the front end). These are quite rare, as these are mostly based on data fed from the controller and not querying the user's permissions directly.
I came up with that solution after reading this post. It provides a good summary on why using the controller is a good idea - and what the alternatives are.
The main reason, why I chose the controller as a place for authorisation checks is that it allows the model (and the data it manages) to be independent of application logic - which includes authorisation.
Please keep in mind, that this is totally dependent on what you want to achieve. I just wanted to show what works for me.
I have a Java web application which stores some data in the session. The data in the session changes as the user interacts with the application (e.g. flow is managed by a controller, each controller has several form pages, on each form page some data is updated in the session and flow goes to the next form page).
The problem is that some users are opening more than one tab to the application, each tab with a different step in the flow. At this point data in the session is messed up since the tabs share the same session (app uses cookie managed sessions).
Telling the users to use different browsers to avoid sharing the same session id (e.g. one Firefox window and one IE window) is not an option since surely at some point somebody will forget to do this and instead use tabs, thus messing up their data.
Adding some verifications that detect that another flow is requested from another tab and display a message to the user saying this is not allowed is not an option either since it pisses of the users and we don't want that do we? :D
The fact is that using another tab is useful for the users because they are more efficient in what they use the application for, so I am keeping this option. But the question now is how best to manage the one session data for the more tabs?
What I thought of, was to have the controller generate a token when it starts the flow and pass this token to each form page which in turn sends it back to identify itself. If another tab requests the same controller action when there is an ongoing flow then generate another token and pass that around.
Basically, I want each flow to have a token and inside the session I won't just keep one set of data but have a set of data for each token and then match requests based on the token.
Now the problem is that this approach will need a lot of rewritings to the application and I was wondering if there is a best practice for managing such a situation or can someone suggest other approaches. I am open to ideas.
Have you encountered this situation? How did you handle it?
This is usually done by assigning a windowId for each tab/window and passing it on each request. Jsf supports this via orchestra. Spring mvc will support it in the next version.
I recently needed this for a simple case, so I implemented it myself. Took half an hour. However, my scope was very limited:
pass a windowId with each request, and return it back for the next request. The first time - generate it.
for any attribute you want to store in the session, put a Map<String, Object> where the key is the windowId
This is exactly what Seam was created to handle. In Seam there's a concept called a Conversation which basically does exactly what you are explaining. Conversations are basically are a way to divide the Session into many pieces that can expire at some timeout. You can look at the source code for org.jboss.seam.core.Manager class to see how it's actually implemented and get inspired ;)
Depending on the complexity of your application, you may want to investigate implementing tabs within your application. This gives you wholesale control over the flow, while still providing users with the functionality they want. I'd argue it's, bugwise, the most robust solution, since you won't have a dependency on the way the browser handles sessions, minimising the number of "known unknowns".
Of course, there'll be potentially a large upfront cost to this, depending on how your application is structured. Without more information about your app, you're the best placed person to decide.
You can also try to wrap your application inside Adobe Air
And then limit your web application to be only accessable from this air. By doing this you dont need to consider the web browser fragmentation and their unique behaviour.