[hibernate-dev] Session and carrying 3rd party state
Gunnar Morling
gunnar at hibernate.org
Mon Mar 31 08:48:45 EDT 2014
2014-03-31 14:35 GMT+02:00 Emmanuel Bernard <emmanuel at hibernate.org>:
> Btw to answer your concern about the event listeners and the use of
> instance of, we could imagine an API like getListenerOfType(Class) on the
> SessionEventListenerManager.
>
Hum, couldn't there be several instances of the same listener type, e.g.
configured differently? Maybe not in our particular case, but such API
would restrict this case.
> Because one key thing that this approach solves and that the map approach
> does not is the actual event listener callback capability on close, flush,
> etc
>
Yes, the map based approach would still need a listener which does these
clean-up things.
>
> On 31 mars 2014, at 12:07, Gunnar Morling <gunnar at hibernate.org> wrote:
>
>
>
>
> 2014-03-20 23:05 GMT+01:00 Emmanuel Bernard <emmanuel at hibernate.org>:
>
>> I took some more time to think about our conversation from 2 IRC meeting
>> ago
>> about offering the ability to carry session bound state not related to
>> ORM per se.
>> Below is a sum and a potential solution.
>> If you are short on time, read Goals, then the SessionSessionEventListener
>> approach and ignore the rest.
>>
>> ## Goals
>>
>> The goal is to be able to carry session bound state for non-ORM projects
>> like search and OGM.
>> We want to avoid ThreadLocal use, in particular when it cannot be
>> protected by a try / catch for proper resource cleaning.
>> We want to avoid a structure that would be shared across threads
>> concurrently
>> i.e. using ConcurrentHashMap with a Weak reference to the session.
>> It needs to be informed of a call to session.clear()
>> It needs to be informed of a call to session.close()
>> The state needs to be accessed from event listener implementations and
>> custom
>> persister / loader implementations i.e. SessionImplementor and maybe
>> EventSource?
>>
>> ## Approaches
>>
>> I'll discuss the approaches we explored in the meeting and then offer an
>> alternative one that I think is pretty interesting and fit better with
>> the current Session model.
>>
>> ### Map
>>
>> This is essentially sticking a map on SessionImpl and use it to carry
>> state.
>> The following is a pseudo implementation
>>
>>
>> /**
>> * interface implemented by SessionImpl and the like
>> */
>> interface SessionCompanion {
>> Object getCompanion(String key);
>> void addCompanion(String key, Object companion);
>> void removeCompanion(String key);
>> }
>>
>>
>> /**
>> * adds a map to the SessionImpl
>> */
>> SessionImpl {
>> private Map<String, Object> companions;
>> public Object getCompanion(String key) { return
>> companions.get(key); }
>> public void addCompanion(String key, Object value) {
>> companions.add(key, companion); }
>> public void removeCompanion(String key) { companions.remove(key) }
>> }
>>
>> The persister or event listener would call SessionCompation.*Companion
>> method
>> to put and retrieve its state.
>>
>> There is no clear / close event listener loop and it would need to be
>> added.
>>
>> ### Delegator
>>
>> Gunnar and teve discussed an approach where the delegator would be passed
>> to
>> the underlying session and be accessible via an `unwrap` method.
>> I have not followed the details but this approach has one major flaw: the
>> delegator (OgmSession, FullTextSession etc) is not always created and thus
>> would not be necessarily available.
>> A somewhat similar idea involving passing the session owner has the same
>> drawback. And another one described by Gunnar in
>> https://hibernate.atlassian.net/browse/OGM-469
>>
>> ### The type-safe map approach
>>
>> This approach is vaguely similar to the Map approach except that the
>> payload is
>> represented and looked up by Class. This has the benefit of not having
>> namespace problems and is generally less String-y.
>>
>>
>> /**
>> * interface implemented by SessionImpl and the like
>> */
>> interface SessionCompanion {
>> T getCompanion(Class<T> type);
>> void addCompanion(Object companion);
>> void removeCompanion(Class<?> type)
>>
>> }
>>
>>
>> SessionImpl {
>> //could also use an array or an ArrayList
>> private Map<Class<?>, Object> companions;
>> public T getCompanion(Class<T> type) { return (T)
>> companions.get(type); }
>> public void addCompanion(Object companion) {
>> companions.add(companion.getClass(), type); }
>> public void removeCompanion(Class<T> type) {
>> companions.remove(type); }
>> }
>>
>> Like in the Map approach, the persister or custom event listener would
>> interact
>> with SessionCompanion.
>> There are open issues like what should be done when two objects of the
>> same
>> type are added to the same session.
>> Likewise the clear / close hook issues need to be addressed.
>>
>> ### the SessionEventListener approach
>>
>> I did not know but there is a concept of `SessionEventListener` which can
>> be
>> added to a `SessionImplementor`. It has hooks that are addressing most of
>> the
>> goals.
>>
>>
>> //interface already exists
>> interface SessionImplementor {
>> public SessionEventListenerManager getEventListenerManager();
>> }
>>
>> //interface already exists
>> public interface SessionEventListenerManager extends
>> SessionEventListener {
>> // add this method to be able to retrieve a specific listener
>> holding some state for a 3rd party project
>> List<SessionEventListener> getSessionEventListeners();
>> }
>>
>> OGM or Search would implement a `SessionEventListener` and attach an
>> instance to a session via `Session.addEventListeners()`.
>> It would require to add a method to retrieve the list of
>> `SessionEventListener`s attached to a `SessionEventListenerManager`.
>>
>> List<SessionEventListeners> listeners =
>> sessionImplementor.getSessionEventListenerManager().getEnlistedListeners();
>> OgmSessionEventListener ogmListener =
>> findOrAddOgmListener(sessionImplementor, listeners);
>> ogmListener.someStuff();
>>
>> ## What about clear and close?
>>
>> We have a few ways to react to these.
>> SessionEventListener is already called back when a flush begins / ends as
>> well as when Session closes.
>> We need to either:
>>
>> - add a clear begins / ends callback
>> - have the third party project add a ClearEventListener which would
>> access the SessionEventListeners and do some magic.
>>
>> The first approach has my preference and would do:
>>
>>
>> public interface SessionEventListener {
>> [...]
>> void clearStart();
>> void clearEnd();
>> }
>>
>> What do you guys think? The SessionEventListener approach feels more
>> natural.
>>
>
> Tbh. I feel maintaining the state with a listener is a bit hacky. How
> would we find "our" listener, I guess it would involve some ugly instanceof
> check?
>
> The map based approaches seem preferable to me (I dislike the "companion"
> naming scheme though). The type-safe map approach is nice, as you say it
> may cause type collisions though and lead to a proliferation of key types.
> How about a combined approach which provides one such typesafe container
> per "client":
>
> public interface SessionAttributes {
>
> <T> T get(Class<T> type);
> <T> T put(Class<T> type, T value);
> <T> T remove(Class<T> type);
> }
>
> And
>
> public interface SessionImplementor {
> ...
> SessionAttributes getAttributes(String integratorId);
> }
>
> And in OGM:
>
> public static final String OGM_COMMON_ATTRIBUTES =
> "org.hibernate.ogm.attributes.common";
> ...
> FooBar fb =
> session.getAttributes(OGM_COMMON_ATTRIBUTES).get(FooBar.class);
>
> This avoids collisions of attributes of the same type between different
> clients such as OGM and Search (there could even be several attribute
> containers used by one client). The SessionAttributes could be instantiated
> lazily upon the first getAttributes() call, avoiding any overhead if the
> functionality is not used.
>
> The clean-up part (if it is required?) could then be done by an
> accompanying SessionEventListener.
>
> --Gunnar
>
>
>>
>> Emmanuel
>> _______________________________________________
>> hibernate-dev mailing list
>> hibernate-dev at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/hibernate-dev
>>
>
>
More information about the hibernate-dev
mailing list