Since Wicket automatically manages session state by serializing the components in my page, I'm left wondering, at which level I should attach my state data. More specifically, it seems like a bug I'm having is caused by the WebApplication object being shared among sessions.
Is the application instance shared between sessions?
Should I always attach session data to the Page instance?
What happens if I reuse components with attached session state on multiple pages? Are those instances shared, i.e. if I set the state on the component on one page, is it carried over to another?
I'm guessing, the third bullet point depends on object identity. What does Wicket use to determine that, equals() (like, is it using a Map)?
The data I attached to the application object is state I would need in many pages, so I didn't attach it to the page objects. Is that the correct way to do it in Wicket?
Yes, that's the point of having an Application object. You can store and access application-wide data (usually config) through your Application subclass at any point.
No. There are cases when you need to share session data across multiple pages where storing it in a Session object is more adequate. (An example could be a user login, which definitely belongs to the session and may be used by any page.) Of course you can pass the data around between the pages but it's not a very good strategy. Where the cutoff point is will be your decision: if data is shared between two pages, you might want to pass it from one to the other, if there are 20 pages, you definitely won't want to.
You're not supposed to reuse component instances across different pages. Of course you'll reuse the class but you'll have to construct a new one on each page. This is exactly where storing data in the Session object might come handy.
To clarify: The number of pages sharing state is an indication of where to put the data, but what really matters is how tightly you want the items sharing data to be coupled:
If you pass data as parameters between pages, they will form a tightly coupled group. Depending on what the pages represent, this might be desirable. An example for this may be a wizard-like sequence of pages, with each page knowing what the pages before and after are.
But in the login example we see the opposite: the component populating the login name (probably some kind of login form) must not know about what other components are going to use it. So the logical solution is to store the login name in the session and let each component fetch it as and when they need it.
There are multiple ways to get hold of the current Session object. Check the documentation of the class to see how.
To summarize the information there: Wicket discourages type-unsafe session properties by not providing generic setProperty-like methods. Instead, you are supposed to extend Session, or for most projects, more adequately, WebSession and place typesafe properties in that class. You then override newSession on your application class.
Related
I'm building my first VueJS application which is intended to be used by hundreds of people in the future. I tried to make the individual components reusable and indpendent as possible. To achieve this i decided to let every component fetch its required data themselves. This works fine but i'm not sure if its best practice. I could also pass the data between the components or even using the 2-way data binding functionality.
The sketch bellow describes one of the situations i have. Note that 1 account has 1..* users. As you can see i need to fetch the accounts to display them in the accountOverviewComponent.
Currently i only fetch the accounts in the accountOverviewComponent and fetch the users when the account edit button by the passed accountId in the accountOverviewComponent is clicked. This way i don't fetch data i don't need at the time.
I can also include the users (god knows which data/relations will be added in future) to the fetch account response as wel so i can pass all required data to the accountShowComponent when a account edit button is clicked. This way i can save requests to the server with the side note that i fetch users of accounts i dont need. A possible disadvantage is that the account is updated in the accountShowComponent and not in the accountOverviewComponent (for example when the accountShowComponent is a modal on top of the accountOverviewComponent. So i need to pass the updatet account back or re-fetch the accounts after a save or something.
As third option I can do the same in option 2 but than with the 2-way data binding which handles the data synchronization between the components. This will probably restrict the usage of the accountShowComponent to cases where the accountShowComponent is used "on top" of a parent which contains the data.
I can also store the data in a Vuex store and update the stores all the time. I read that this is bad practive as it should be only used for data which is required accros the SPA. I think Vuex is overkill in "simple" situations like this?
What is the best practice of the described situation? I have a bunch of comparable situations/scenarios in my application. Performance (also for mobile devices), scalability and being "future proof" (extendability/modularity) are important for me. Can someone help me out because i'm a bit lost in the options i have?
UPDATE
The reason i think Vue is overkill is comming from this article which makes totally sense from a software engineer perspective to me (i may be wrong). As my components have a kind of "parent - child" relation so i can solve my "issue" easily with passing data (or use 2-way data binding) and callback-events.
The number one use case for storing data in a centralized store like Vuex, is, because the data must be accessible in multiple places of your application, by components which oftentimes are not related in any way (they neither are parents or children of each other). An example of this would be certain user settings to configure how your application looks or what date format should be used, to name a concrete example.
What are the major disadvantages in using a form bean with session scope in struts 1.x?
You need to implement reset() if your form contains attributes populated from checkboxes. You don't need that to request-scoped form beans.
You need to reset the form to its default values if you show a creation form for the second time, else the creation form will redisplay the data coming from the last created/updated object.
You can't have two browser tabs or frames using the same form, because they will walk on each other's toes.
Form beans should be in the request scope by default.
Just try to work with both scopes and choose one preferred for yourself. But I should say there is small difference when you are working with persistent objects (and ORM tools like Hibernate), just because properties are persisted in database between requests.
Infamous checkboxes (and corresponding boolean properties). If you are working with persistent objects (editing boolean properties of some entity), you'll need extra code to reset checkboxes anyways. Scope doesn't matter because boolean property is persistent (isn't cleared automatically between requests).
When you are working with complex persistent objects (hierarchies of objects, mapped by Hibernate onto set of related database tables), often you'll just nest persistent object into form-bean and use nested properties, e.g. <html:text property="purchase.client.name" /> (of course, you can create getters/setters in form-bean for each property of the entire hierarchy, but this is tedious and will complicate further development). For creation you'll just create new empty purchase object in form-bean, for edition you'll load existing purchase from database (request for edit will contain some identifier of object you want to change). Scope doesn't matter again.
About two browser tabs. More important and underestimated problem arises with usage of AJAX requests, especially when they are not idempotent and are overlapped in time (browser issues request for update 1, then request for update 2, while update 1 is still processed on server) - although it is very strange design (I mean overlapping update requests simultaneously in one session from one user). Yes, in that case you'll need to separate data in different requests. But moreover, your action (if we are talking about Struts 1) should be thread-safe, and your business logic should be ready to concurrent/conflicting updates (solve synchronization problems, lock objects, merge/override/reject updates etc.). If you are developing multi-user application, this may happen also when two different users want to change the same object simultaneously. Again, bean scope has little importance comparing to the whole problem.
As you can see, there is only one disadvantage with session-scoped form bean, and it arises only in relation to serious design flaw (overlapping update requests from one user).
Is it possible to have one model that you break up into several views so that the user is not overwhelmed by the amount of data they will need to input? I'm trying to build a turbo tax like interface where a question or two are asked, then the user clicks next to answer the next set of questions and so on.
The Model doesn't seem make sense to break up into more models. Since it is a single distinct entity, like a questionnare.
See similar question for a nice example:
multi-step registration process issues in asp.net mvc (splitted viewmodels, single model)
It is possible to use the same model for multiple views, but you should decide how you want to preserve the state as you go though this "wizard". One approach can be to cross-post between the views and keep the state in post data, but in that case you have to add a lot of hidden fields for all model properties that are otherwise not displayed in an input on the current view. Another approach can be to persist the partially filled model, with the additional benefit, that the user might be able to continue after a session timeout or another problem, but then you might need to clean up stale data and be flexible in the validation on the database level. You can also preserve the state in the session if you want. Finally, you can also keep the state in the browser independent from the post data and do only AJAX calls with the server until you reach the point when you want to save everything.
Throughout the application I need to access User object (Doctrine) several times per execution (I mean each time page is displayed) so on some, and instead of retrieving it from database every time, I thought it would be better to store it once and then reuse it.
Can I store it in sfContext?
Symfony discourages saving objects into the session, see here for example: http://www.symfony-project.org/gentle-introduction/1_4/en/06-Inside-the-Controller-Layer#chapter_06_sub_accessing_the_user_session
... But you can save user_ids and other bits that save on queries. It really depends on whether the things you need to do on all those pages require the entire user object. If yes, $this->getUser()->getGuardUser() is what you'll end up using everywhere.
If you're referring to the currently logged in user object, it should already automatically be loaded for you. At the point of authentication, the system loads the user record and it will remain there in the session.
In actions, you can retrieve the user object with:
$this->getUser()
In a view, it's already loaded into the variable:
$sf_user
I've got a cfc to handle the user object. My question is: is it better to store just the user_id in the session and create the user object anew with each request? Or is is better to store the whole user object in the session?
Here are my thoughts either way:
If I store the whole object in the session:
There will be potentially less processor overhead
There will be potentially more memory overhead
all of the methods/functions are stored in the actual object, and new functions that I update in the cfc will not be available unless users logout and back in, or if I devise some way to make it refresh itself.
There could potentially be mutex or lock problems if I'm messing with the object via concurrent ajax calls
If I store just the user_id in the session:
I'll have to create the user object with each page request (potentially more processor overhead)
There will be potentially less memory overhead
There won't be a chance for mutex/lock/race conditions since each request will have its own copy of the user object
Updates to the CFC model itself will be immediately recognized across the system and users wouldn't have to log out and back in
Is there a normal practice for this sort of thing? Am I over-thinking it?
All of the CF apps I've written were targeted at high traffic levels and high availability, so we never had the luxury of being able to think about single-server practices.
So, in my experience, I always had to a) allow for multiple load-balanced servers, and b) avoid sticky-sessions on the load balancer for a number of reasons. Therefore, we needed to, at the very least, have a server become part of a cluster on the fly and pick up mid-session traffic.
So, we always pulled "session" data from a shared datastore on every request.
My suggestion is to implement a session facade.
This affords you the option to change how you persist session data (like the user record) without changing the rest of your app.
You can choose, behind the scenes, to store everything in the session scope, load it up for every request, do a hybrid, use a key-value store, whatever.
You can choose whether to eager-load data, or lazy-load data, or any mix in between, and the rest of the app doesn't need to be aware of what you've done.
On Race Conditions
If you're concerned about race conditions then I would suggest using named locks around data commit and access. This is another bonus of using a facade - your application code doesn't need to know about this, and you can choose to put locks around certain objects, as opposed to locking the whole session.
You haven't indicated whether you're using an ORM, so this is a general answer.
For typical applications, I recommend instantiating the user object into the session scope. There's a big downside to creating the object anew with each request that you didn't include in your list: changes to the user object's properties and state will not persist across requests unless you intend to flush the user object's state to your persistence layer (e.g. database) on every hit. That is likely to be a much more expensive operation than object instantiation, and it doesn't necessarily insulate you from the kinds of problems you're thinking about with respect to ajax calls, race conditions, etc -- it just transfers the manifestation of those problems to the persistence layer, where your object's data could be in an unpredictable state.
Since every new request would be an "implicit save", you would also have to design your "ephemeral" object to be able to persist itself regardless of whether it's in a valid state (imagine the case of a multi-page form that modifies some aspect of the user object).
For session-stored objects, your concerns about memory can be mitigated by careful design practices. For instance, if your user has many tasks, and each task has many items, it might be a bad idea to instantiate and compose all those objects into your user object (i.e., lazy loading would be a better approach than eager loading).
If you really must to be able to change your CFCs on the fly, you can achieve that goal even with session-stored objects. One way is to store a version flag in both the application and session. With each request, your app would compare those flags. When they differ, the app would run a session-reload routine that snapshots current properties, rebuilds the session-stored objects, and finally updates the session flag to match the application flag.
This is piggy-backing partially off Ken Redler's answer but I don't have enough reputation to comment.
The way we do it, and the way I prefer, is to store the user data in Session as a struct. Then on request start, our Auth Model creates the user object in the Request scope and overrides any default values with the Session data. There are a few advantages to this:
Less hits to the database, less CPU
Always run newest code without a complex custom system ensuring that
Clustered environment friendly (complex objects in Session can't be clustered)
Can add or remove properties without corruption (assuming your User object only updates dirty columns)
Also, if you're using CF9, one of the features they were really proud of is how much they optimized object instantiation. If you haven't, test it yourself!
It depends.
If you have a lot of traffic - in the thousands of unique visitors per minute range - the memory overhead of storing your User.cfc in the session will eventually weigh you down. This can be easily overcome by throwing hardware at it (more memory for a while, eventually more servers and a hardware load balancer). Of course popularity is a good problem to have.
If you seem to have a CPU, network or other bottleneck in your database space, you may want to have the object cached in session memory so that you have fewer hits to the database.
Why do I mention these scenarios? You may be prematurely optimizing - don't fix a problem that you don't have. Don't optimize your memory, CPU and database access until those are, or soon will be, problems.
Now from an architectural best practice - not from an optimized "what's best for my processor" - well, I can only say: It depends.
Truthfully, neither way is wrong. If you are going to find yourself needing to check credentials against your database on every request, don't cache it. If you like the feel of an object in the session, then cache it. Because you know your own domain, you can probably go back and forth all day on why you should or should not cache the user object in the session. If it's going to make it easier, do it. If it's going to make it harder, don't.
I would just warn you against doing something incredibly convoluted or anything that is not immediately obvious to a developer looking at your application - the more you write, the more you have to maintain forever, the more your co-workers will associate your name with evil.
Finally, last note, if this is a vote - I say you cache it. It makes sense and always feels good to call session.user.hasRole("xyz") or the like.