Re: AW: Session Storage with Tapestry
On Wed, 18 Mar 2015 11:14:08 -0300, Poggenpohl, Daniel wrote: What I meant to say was they recommend @SessionState instead of @SessionAttribute because it is a complex object. Who said that? Anyway, I think it's an incorrect statement. It should say "@SessionAttribute for primitive types and general-purpose classes like String and Date, @SessionState for everything else". String is a pretty complex class and it shouldn't be used with @SessionState. one of my DAO services into my AppSession object. Nope. You just need to call it in your layout class, probably in its setupRender() method. Or wouldn't this work because my AppSession is not a page or component? It would, but I don't like the idea of injecting data storage objects into session-persisted objects at all. If this wouldn't work, then every time someone would use my AppSession user, he would have to get() the user and then do a manual merge() or via DAO on it. Nope, just once per request, hence my suggestion on doing it on setupRender() of your Layout class. @SessionState private AppSession appSession; @Inject private EntityManager entityManager; void setupRender() { appSession.setUser(entityManager.merge(appSession.getUser()); } -- Thiago H. de Paula Figueiredo Tapestry, Java and Hibernate consultant and developer http://machina.com.br - To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org
AW: Session Storage with Tapestry
Hi, > You need to use @SessionState because @Persist is only valid for a given page > or component. Page1's @Persist private > User user; is stored in a different session attribute than Page2's @Persist > private User user;. If you want something > persisted across pages, you need to use @SessionState. > Being a complex object makes no difference about choosing one annotation or > the other. Because I feared this answer would arrive, I separated my two topics Session and Memory into two separate mails :-) What I meant to say was they recommend @SessionState instead of @SessionAttribute because it is a complex object. I never intended to use @Persist with the session state objects. > @SessionState is keyed by type, not by field name, so @SessionState private > User user; and @SessionState private User > currentUser; will point to the same object, stored in the same session > attribute. Just as I thought, thank you. > The error isn't related to transactions nor Tapestry at all. It's related to > your Hibernate/JPA usage: one entity is loaded in > one request, one Hibernate session/JPA entity manager instance. Then, in > another request, another session/entity > manager instance, you try to load some lazy field. > You need to use the merge() method of org.hibernate.Session or EntityManager > to reattach the entity to the current > Hibernate session or JPA entity manager. I've since reduced the @SessionState object to a user and removed the AppSession object because the login time was never used anywhere anyway. I hate it when people program something just because they think someone may need it some day. This of course fixed the bug. If I'd use the merge() method, I'd have to inject an EntityManager or one of my DAO services into my AppSession object. Or wouldn't this work because my AppSession is not a page or component? If this wouldn't work, then every time someone would use my AppSession user, he would have to get() the user and then do a manual merge() or via DAO on it. Can I inject into my AppSession object or what would be the way to go here? Regards, Daniel P. -Ursprüngliche Nachricht- Von: Thiago H de Paula Figueiredo [mailto:thiag...@gmail.com] Gesendet: Mittwoch, 18. März 2015 14:17 An: Tapestry users Betreff: Re: Session Storage with Tapestry On Wed, 18 Mar 2015 07:21:06 -0300, Poggenpohl, Daniel wrote: > Hello again, Hi! > I need a session storage where I store the currently logged on user. > Reading about it in the documentation, they recommend using > @SessionState because my user is a complex object, also containing > lists of other entities. You need to use @SessionState because @Persist is only valid for a given page or component. Page1's @Persist private User user; is stored in a different session attribute than Page2's @Persist private User user;. If you want something persisted across pages, you need to use @SessionState. Being a complex object makes no difference about choosing one annotation or the other. > My user also is an entity in a database. So, when a user logs in, the > appropriate entity is retrieved from the database, an "AppSession" > object is created containing, among e.g. the time of login, the user > object. Is this the right way to do it? Or should I only store the ID > in the session? This is extremely dependent on how you're going to use your user information. If you're going to show their name in every page, for example, and you store just the id, you'll be querying the database for the same information every request (unless you use some kind of cache between your page or component or mixin and your database). > Now when the SessionState object is created, it can be used in any > other page or component using the same SessionState annotation and the > same type. Does it need to be the same name I'd say it doesn't, as > I've not read otherwise. @SessionState is keyed by type, not by field name, so @SessionState private User user; and @SessionState private User currentUser; will point to the same object, stored in the same session attribute. > To do this, a service receives the user. The service tries to access > the lazy collection, but fails with a "failed to lazily initialize a > collection of role:". > What I gather from this is, services don't operate within transactions? The error isn't related to transactions nor Tapestry at all. It's related to your Hibernate/JPA usage: one entity is loaded in one request, one Hibernate session/JPA entity manager instance. Then, in another request, another session/entity manager instance, you try to load some lazy field. You need to use the merge() method of org.hibernate.Session or EntityManager to reattach t
Re: Session Storage with Tapestry
On Wed, 18 Mar 2015 07:21:06 -0300, Poggenpohl, Daniel wrote: Hello again, Hi! I need a session storage where I store the currently logged on user. Reading about it in the documentation, they recommend using @SessionState because my user is a complex object, also containing lists of other entities. You need to use @SessionState because @Persist is only valid for a given page or component. Page1's @Persist private User user; is stored in a different session attribute than Page2's @Persist private User user;. If you want something persisted across pages, you need to use @SessionState. Being a complex object makes no difference about choosing one annotation or the other. My user also is an entity in a database. So, when a user logs in, the appropriate entity is retrieved from the database, an "AppSession" object is created containing, among e.g. the time of login, the user object. Is this the right way to do it? Or should I only store the ID in the session? This is extremely dependent on how you're going to use your user information. If you're going to show their name in every page, for example, and you store just the id, you'll be querying the database for the same information every request (unless you use some kind of cache between your page or component or mixin and your database). Now when the SessionState object is created, it can be used in any other page or component using the same SessionState annotation and the same type. Does it need to be the same name I'd say it doesn't, as I've not read otherwise. @SessionState is keyed by type, not by field name, so @SessionState private User user; and @SessionState private User currentUser; will point to the same object, stored in the same session attribute. To do this, a service receives the user. The service tries to access the lazy collection, but fails with a "failed to lazily initialize a collection of role:". What I gather from this is, services don't operate within transactions? The error isn't related to transactions nor Tapestry at all. It's related to your Hibernate/JPA usage: one entity is loaded in one request, one Hibernate session/JPA entity manager instance. Then, in another request, another session/entity manager instance, you try to load some lazy field. You need to use the merge() method of org.hibernate.Session or EntityManager to reattach the entity to the current Hibernate session or JPA entity manager. Services operate within transactions as long as you use @CommitAfter (tapestry-hibernate or tapestry-jpa) or something like that (other library). -- Thiago H. de Paula Figueiredo Tapestry, Java and Hibernate consultant and developer http://machina.com.br - To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org
Re: Session Storage with Tapestry
For this to work you need to store an entity in the SessionState. It looks like you are storing AppSession in the SessionState which contains the User entity. The simple way to fix this would be to add a lastLogin property to your User entity and then just make your SessionState a User object. If you don't want lastLogin in the database you'll need to persist it some other way. I usually make a service to hide all this stuff. I don't like having @SessionState everywhere because it makes it difficult to refactor. In this case you could make a service called UserSession with getAppSession() and getUser(). Then instead of putting User in AppSession just put both in the session. On Wednesday, March 18, 2015, Poggenpohl, Daniel < daniel.poggenp...@isst.fraunhofer.de> wrote: > Hello again, > > oops, I didn't see this message, sorry. > This here: > > http://tapestry.apache.org/5.3/apidocs/src-html/org/apache/tapestry5/jpa/JpaModule.html > seems to indicate that the default for > JpaSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED > is "true", which is part of why my changes do not make a difference. > > Another part seems to be what you say, that I need to directly annotate an > entity with @SessionState. > > I've found this here: > > http://tapestry.apache.org/5.3/apidocs/src-html/org/apache/tapestry5/internal/hibernate/EntityApplicationStatePersistenceStrategy.html#line.40 > > public class EntityApplicationStatePersistenceStrategy extends > SessionApplicationStatePersistenceStrategy > { > @Override > public T get(final Class ssoClass, final > ApplicationStateCreator creator) > { > final Object persistedValue = getOrCreate(ssoClass, creator); > > if (persistedValue instanceof PersistedEntity) > { > final PersistedEntity persisted = (PersistedEntity) > persistedValue; > > final Object restored = > persisted.restore(entityManagerManager); > > // shall we maybe throw an exception instead? > if (restored == null) > { > set(ssoClass, null); > return (T) getOrCreate(ssoClass, creator); > } > > return (T) restored; > } > > return (T) persistedValue; > } > } > > Which tells me that entities contained in SSO annotated objects are > basically out of luck, it seems. > > So, is my method of creating a session state object containing multiple > values not a good way to do this? > Or is it just that entities are used under-supported this way? > > Regards, > Daniel P. > > -Ursprüngliche Nachricht- > Von: Barry Books [mailto:trs...@gmail.com ] > Gesendet: Mittwoch, 18. März 2015 12:05 > An: Tapestry users > Betreff: Re: Session Storage with Tapestry > > If you are using Tapestry Hibernate it should just work if you put a > Hibernate object into a SessionState variable. There is a configuration > that contains the Hibernate entities so SessionState is able to store the > primary key in the session and retrieve the object when needed. Services as > well as pages/components should be able to lazy load from the SessionState > object. > > Assuming you are using Tapestry Hibernate then somehow the object in your > SessionState is disconnected from the Hibernate session. If you turn on > show sql you should see the object fetched evertime you go to a new page. > If you don't then something is wrong. > > > > On Wed, Mar 18, 2015 at 5:21 AM, Poggenpohl, Daniel < > daniel.poggenp...@isst.fraunhofer.de > wrote: > > > Hello again, > > > > a slightly different topic as the last but with the same "undertones": > > > > I need a session storage where I store the currently logged on user. > > Reading about it in the documentation, they recommend using > > @SessionState because my user is a complex object, also containing > > lists of other entities. > > > > My user also is an entity in a database. So, when a user logs in, the > > appropriate entity is retrieved from the database, an "AppSession" > > object is created containing, among e.g. the time of login, the user > > object. Is this the right way to do it? Or should I only store the ID in > the session? > > > > Now when the SessionState object is created, it can be used in any > > other page or component using the same SessionState annotation and the > same type. > > Does it need to be the same name > > I'd say it doesn't, as I've not read otherwise. > > > > My user contains lazy collections of other entities. Every page of my > >
AW: Session Storage with Tapestry
Hello again, oops, I didn't see this message, sorry. This here: http://tapestry.apache.org/5.3/apidocs/src-html/org/apache/tapestry5/jpa/JpaModule.html seems to indicate that the default for JpaSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED is "true", which is part of why my changes do not make a difference. Another part seems to be what you say, that I need to directly annotate an entity with @SessionState. I've found this here: http://tapestry.apache.org/5.3/apidocs/src-html/org/apache/tapestry5/internal/hibernate/EntityApplicationStatePersistenceStrategy.html#line.40 public class EntityApplicationStatePersistenceStrategy extends SessionApplicationStatePersistenceStrategy { @Override public T get(final Class ssoClass, final ApplicationStateCreator creator) { final Object persistedValue = getOrCreate(ssoClass, creator); if (persistedValue instanceof PersistedEntity) { final PersistedEntity persisted = (PersistedEntity) persistedValue; final Object restored = persisted.restore(entityManagerManager); // shall we maybe throw an exception instead? if (restored == null) { set(ssoClass, null); return (T) getOrCreate(ssoClass, creator); } return (T) restored; } return (T) persistedValue; } } Which tells me that entities contained in SSO annotated objects are basically out of luck, it seems. So, is my method of creating a session state object containing multiple values not a good way to do this? Or is it just that entities are used under-supported this way? Regards, Daniel P. -Ursprüngliche Nachricht- Von: Barry Books [mailto:trs...@gmail.com] Gesendet: Mittwoch, 18. März 2015 12:05 An: Tapestry users Betreff: Re: Session Storage with Tapestry If you are using Tapestry Hibernate it should just work if you put a Hibernate object into a SessionState variable. There is a configuration that contains the Hibernate entities so SessionState is able to store the primary key in the session and retrieve the object when needed. Services as well as pages/components should be able to lazy load from the SessionState object. Assuming you are using Tapestry Hibernate then somehow the object in your SessionState is disconnected from the Hibernate session. If you turn on show sql you should see the object fetched evertime you go to a new page. If you don't then something is wrong. On Wed, Mar 18, 2015 at 5:21 AM, Poggenpohl, Daniel < daniel.poggenp...@isst.fraunhofer.de> wrote: > Hello again, > > a slightly different topic as the last but with the same "undertones": > > I need a session storage where I store the currently logged on user. > Reading about it in the documentation, they recommend using > @SessionState because my user is a complex object, also containing > lists of other entities. > > My user also is an entity in a database. So, when a user logs in, the > appropriate entity is retrieved from the database, an "AppSession" > object is created containing, among e.g. the time of login, the user > object. Is this the right way to do it? Or should I only store the ID in the > session? > > Now when the SessionState object is created, it can be used in any > other page or component using the same SessionState annotation and the same > type. > Does it need to be the same name > I'd say it doesn't, as I've not read otherwise. > > My user contains lazy collections of other entities. Every page of my > app contains the layout component which provides the login area and > serves to create the session object for the app, retrieving the user > entity in the process. > A page containing the layout component itself contains another > component where these lazy collections are needed. The user logs in, > the SessionState object is created, the user entity is stored inside > the object. The page is requested again, and the component is > initialized/rendered. The component contains a reference to the > SessionState object. Inside the component, a tree should display objects of > the lazy collection. > To do this, a service receives the user. The service tries to access > the lazy collection, but fails with a "failed to lazily initialize a > collection of role:". > > What I gather from this is, services don't operate within transactions? > > UPDATE: I tried to access the lazy collection from the component > itself, but the error was the same. > Even from the page, the error still was present. > > This leads me to the point that I may be doing something wrong using > an entity in a session storage? > > Regards, > Daniel Poggenpohl >
AW: Session Storage with Tapestry
Hi, I've read about the Hibernate entity persistence strategy on http://tapestry.apache.org/hibernate-user-guide.html As I do not want to be Hibernate-specific, I searched for an equivalent for JPA and found it not in the guide, but searching in Eclipse: JpaSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED This seems to enable the entity persistence strategy for session state objects. Applying this doesn't make the error go away, though. I'm gonna include some code excerpts here, maybe I've done something horribly wrong. In AppModule: public static void contributeApplicationDefaults( MappedConfiguration configuration) { configuration.add(JpaSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED, "true"); } My session state object: public class AppSession { private User loggedInUser; private Date loginDate; public AppSession(User loggedInUser) throws ClientProtocolException, IOException { this.loggedInUser = loggedInUser; this.loginDate = new Date(); } public User getLoggedInUser() { return loggedInUser; } public Date getLoginDate() { return loginDate; } } The user entity: @Entity @NamedQueries ({ @NamedQuery(name=User.FIND_BY_USERNAME, query="SELECT u FROM User u WHERE u.username = ?1") }) public class User { public static final String FIND_BY_USERNAME = "User.findByUserName"; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @NonVisual private long id; @Validate(value="required") @Column(nullable=false,unique=true) private String username; @Lob @Column(nullable=false) private byte[] password; @Column(nullable=false) @Validate(value="email") private String email; @ManyToMany @JoinTable private Set groups; public User() { groups = new HashSet(); } public Set getGroups() { return Collections.unmodifiableSet(groups); } Creating the session in my layout component (excerpt): @SessionState AppSession session; public Object onActionFromLogout() { session = null; return Index.class; } void onValidateFromLoginForm() { authenticatedUser = appAuthenticator.authenticateUser(userName, password); } Object onSuccessFromLoginForm() { session = new AppSession(authenticatedUser); } Authenticating a user: public User authenticateUser(String username, String password) throws NoExistingUserException, CryptoUtilException { User user = userDAO.findUserByName(username); return CryptoUtil.checkHash(CryptoUtil.calculateHash(password), user.getPassword()) ? user : null; Using the session state object in a page: public class Hauptseite { @SessionState private AppSession session; void setupRender() { for (UserGroup group : session.getLoggedInUser().getGroups()) { System.out.println(group.toString()); } } Any pointers? Do I have to use the user as a direct SessionState object? Can't I use a wrapper class? Regards, Daniel P. Von: Poggenpohl, Daniel Gesendet: Mittwoch, 18. März 2015 11:21 An: users@tapestry.apache.org Betreff: Session Storage with Tapestry Hello again, a slightly different topic as the last but with the same "undertones": I need a session storage where I store the currently logged on user. Reading about it in the documentation, they recommend using @SessionState because my user is a complex object, also containing lists of other entities. My user also is an entity in a database. So, when a user logs in, the appropriate entity is retrieved from the database, an "AppSession" object is created containing, among e.g. the time of login, the user object. Is this the right way to do it? Or should I only store the ID in the session? Now when the SessionState object is created, it can be used in any other page or component using the same SessionState annotation and the same type. Does it need to be the same name I'd say it doesn't, as I've not read otherwise. My user contains lazy collections of other entities. Every page of my app contains the layout component which provides the login area and serves to create the session object for the app, retrieving the user entity in the process. A page containing the layout component itself contains another component where these lazy collections are needed. The user logs in, the SessionState object is created, the user entity is stored inside the object. The page is requested again, and the component is
Re: Session Storage with Tapestry
If you are using Tapestry Hibernate it should just work if you put a Hibernate object into a SessionState variable. There is a configuration that contains the Hibernate entities so SessionState is able to store the primary key in the session and retrieve the object when needed. Services as well as pages/components should be able to lazy load from the SessionState object. Assuming you are using Tapestry Hibernate then somehow the object in your SessionState is disconnected from the Hibernate session. If you turn on show sql you should see the object fetched evertime you go to a new page. If you don't then something is wrong. On Wed, Mar 18, 2015 at 5:21 AM, Poggenpohl, Daniel < daniel.poggenp...@isst.fraunhofer.de> wrote: > Hello again, > > a slightly different topic as the last but with the same "undertones": > > I need a session storage where I store the currently logged on user. > Reading about it in the documentation, they recommend using @SessionState > because my user is a complex object, also containing lists of other > entities. > > My user also is an entity in a database. So, when a user logs in, the > appropriate entity is retrieved from the database, an "AppSession" object > is created containing, among e.g. the time of login, the user object. Is > this the right way to do it? Or should I only store the ID in the session? > > Now when the SessionState object is created, it can be used in any other > page or component using the same SessionState annotation and the same type. > Does it need to be the same name > I'd say it doesn't, as I've not read otherwise. > > My user contains lazy collections of other entities. Every page of my app > contains the layout component which provides the login area and serves to > create the session object for the app, retrieving the user entity in the > process. > A page containing the layout component itself contains another component > where these lazy collections are needed. The user logs in, the SessionState > object is created, the user entity is stored inside the object. The page is > requested again, and the component is initialized/rendered. The component > contains a reference to the SessionState object. Inside the component, a > tree should display objects of the lazy collection. > To do this, a service receives the user. The service tries to access the > lazy collection, but fails with a > "failed to lazily initialize a collection of role:". > > What I gather from this is, services don't operate within transactions? > > UPDATE: I tried to access the lazy collection from the component itself, > but the error was the same. > Even from the page, the error still was present. > > This leads me to the point that I may be doing something wrong using an > entity in a session storage? > > Regards, > Daniel Poggenpohl >
Session Storage with Tapestry
Hello again, a slightly different topic as the last but with the same "undertones": I need a session storage where I store the currently logged on user. Reading about it in the documentation, they recommend using @SessionState because my user is a complex object, also containing lists of other entities. My user also is an entity in a database. So, when a user logs in, the appropriate entity is retrieved from the database, an "AppSession" object is created containing, among e.g. the time of login, the user object. Is this the right way to do it? Or should I only store the ID in the session? Now when the SessionState object is created, it can be used in any other page or component using the same SessionState annotation and the same type. Does it need to be the same name I'd say it doesn't, as I've not read otherwise. My user contains lazy collections of other entities. Every page of my app contains the layout component which provides the login area and serves to create the session object for the app, retrieving the user entity in the process. A page containing the layout component itself contains another component where these lazy collections are needed. The user logs in, the SessionState object is created, the user entity is stored inside the object. The page is requested again, and the component is initialized/rendered. The component contains a reference to the SessionState object. Inside the component, a tree should display objects of the lazy collection. To do this, a service receives the user. The service tries to access the lazy collection, but fails with a "failed to lazily initialize a collection of role:". What I gather from this is, services don't operate within transactions? UPDATE: I tried to access the lazy collection from the component itself, but the error was the same. Even from the page, the error still was present. This leads me to the point that I may be doing something wrong using an entity in a session storage? Regards, Daniel Poggenpohl