{"id":278,"date":"2011-11-26T00:39:16","date_gmt":"2011-11-25T23:39:16","guid":{"rendered":"http:\/\/doanduyhai.wordpress.com\/?p=278"},"modified":"2018-09-14T13:59:35","modified_gmt":"2018-09-14T13:59:35","slug":"hibernate-longextended-session","status":"publish","type":"post","link":"https:\/\/www.doanduyhai.com\/blog\/?p=278","title":{"rendered":"JPA\/Hibernate Global Conversation with Spring AOP"},"content":{"rendered":"<p>The previous 2 articles were dedicated to the analysis of Spring @Transactional and @PersistenceContext internals.<\/p>\n<p>In this article we will discuss about the JPA <strong>extended persistence context<\/strong> (<em>Hibernate long session<\/em>) pattern.\u00a0 We&#8217;ll look at the pros and cosn and finally I will show a practical implementation using the <strong>TransactionSynchronizationManager<\/strong> class shown earlier in both articles<br \/>\n<!--more--><br \/>\nFirst, if you&#8217;ve missed the articles about Spring annotation, have a look here:<\/p>\n<ul>\n<li><a title=\"Spring @Transactional explained\" href=\"https:\/\/www.doanduyhai.com\/blog\/?p=95\" target=\"_blank\">Spring @Transactional explained<\/a><\/li>\n<li><a title=\"Spring @PersistenceContext\/@PersistenceUnit explained\" href=\"https:\/\/www.doanduyhai.com\/blog\/?p=222\" target=\"_blank\">Spring @PersistenceContext\/@PersistenceUnit explained<\/a><\/li>\n<\/ul>\n<blockquote><p>The following implementation is based on<strong> Spring 3.0.5<\/strong> official release + <strong>JPA 2\/Hibernate 3.5.2<\/strong> in a WEB <strong>J2SE<\/strong> environment. If you are running applications on a J2EE platform, you should rely on transaction management facilities provided by the J2EE engine itself<\/p><\/blockquote>\n<p>Before going further, let&#8217;s define some notions:<\/p>\n<ul>\n<li>by <em><strong>session<\/strong><\/em> we mean <strong>Hibernate session<\/strong> (e.g. equivalent of entity manager)<\/li>\n<li>by <em><strong>user session<\/strong><\/em> we mean the user data context on the server. It includes all user data and session-scoped beans<\/li>\n<li>by<em><strong> persistence context<\/strong><\/em>, we mean a set of entities that are managed by the <strong>EntityManager<\/strong>. Sometimes people tend to use EntityManager when they mean persistence context.<\/li>\n<li>by <em><strong>transaction<\/strong><\/em> we mean <strong>JDBC transaction<\/strong>, not user transaction (<em>unit-of-work <\/em>or<em> conversation<\/em>). A <strong>transaction<\/strong> can be started by an <strong>EntityManager<\/strong> within a persistence context. Within the same persistence context, several <strong>transactions<\/strong> can exist, provided that their lifespan does not overlap since JPA does not support nested <strong>transactions<\/strong><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h1>I The need for a long\/extended session<\/h1>\n<p>The problem with the classical <em>session-per-request<\/em> or <strong>OSIV<\/strong> (Open Session In View) patterns is that for each new request made by the client browser to the server, a new <strong>EntityManager<\/strong> is created, attached to the current Thread using a ThreadLocal and is passed along all layers down to the DAOs. Once the response is sent back to the client browser, this <strong>EntityManager<\/strong> is closed so all entities that have been retrieved from the database are now in <strong>detached<\/strong> mode.<\/p>\n<p>There are many drawbacks being in detached mode:<\/p>\n<ol>\n<li>the state of entities is <em>not managed<\/em>. Any modification to the field or collections on the entities is ignored by Hibernate while in detached mode. The next time they are re-attached to another <strong>EntityManager<\/strong>, all the modifications are lost<\/li>\n<li>the re-attachment of the entity itself is not that easy with the current state of JPA specs. JPA API does expose\u00a0 a <em>detach()<\/em> method on <strong>EntityManager<\/strong> but there is no <em>re-attach()<\/em>or something similar.\n<ul>\n<li>one solution is to use <em>merge()<\/em> but <em>merge()<\/em> is not re-attaching your old detached entity, it copies all its state to a fresh entity created from scratch, synchronizing it with the database and returns the Java reference of the new entity. If your old detached entity is still referenced by other classes (service\/DAO\/presentation layers) you should update the reference with the new entity, which is quite cumbersome<\/li>\n<li>the other work-around is to use <em>session.saveOrUpdate(detachedEntity) <\/em>but it is worst because it will trigger sometimes UPDATE statement to the database since Hibernate does not know whether the state of this entity has changed or not while it was detached. Furthermore you need to do it on all detached entities so somehow you need to keep track (in a List) of all entities that may be detached to re-attach them automatically. Again this is very error-prone<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>The ultimate idea is to avoid detaching entities, keep them in the persistence context and let the <strong>EntityManager<\/strong> manage as long as the user <em>unit-of-work<\/em> lasts.<\/p>\n<p>The difficulty now is where to store this opened <strong>EntityManager<\/strong> whose lifespan spreads across several client-server requests. Furthermore, we need to bind each living EntityManager to the correct user session. The natural placeholder is the <strong>HttpSession<\/strong> map.<br \/>\n&nbsp;<\/p>\n<h1>II\u00a0 Pre-requisites<\/h1>\n<p>With global conversation, we need to:<\/p>\n<ol>\n<li><span style=\"color:#ff0000;\"><strong>Clearly identify end-user conversation scenarios<\/strong><\/span>. An extended persistence context does not make sense if the developer cannot sketch out distinct web navigation scenarios and use cases.<\/li>\n<p>&nbsp;<\/p>\n<li><strong><span style=\"color:#ff0000;\">List all possible entry points for new conversations and their exit points<\/span><span style=\"color:#ff0000;\"> to flush and close the EntityManager<\/span><\/strong>. Every conversation should have an exit point otherwise the <strong>EntityManager<\/strong> will never be closed and you&#8217;ll run into big trouble (<em>OutOFMemoryException<\/em> at least).<\/li>\n<p>&nbsp;<\/p>\n<li><span style=\"color:#ff0000;\"><strong>Manage carefully the growth of the persistence context<\/strong><\/span>. Since the <strong>EntityManager<\/strong> lives across several user Web requests, the persistence context tends to grow bigger and bigger. You should load in the persistence context as few entities as possible, only those that are necessary for the current conversation.<\/li>\n<p>&nbsp;<\/p>\n<li><strong><span style=\"color:#ff0000;\">Usage of secondary level cache is strongly advised<\/span><\/strong> to discharge the <strong>EntityManager<\/strong> the burden of caching frequently used referential data.<\/li>\n<p>&nbsp;<\/p>\n<li>When you need to request data in the DB necessary for the logic of the user operations (<em>functional code<\/em> or <em>label<\/em> for\u00a0 instance), <span style=\"color:#ff0000;\"><strong>prefer<\/strong><strong> <a title=\"scalar queries\" href=\"http:\/\/docs.jboss.org\/hibernate\/entitymanager\/3.5\/reference\/en\/html\/objectstate.html#d0e1136\">scalar queries<\/a><\/strong><\/span> <span style=\"color:#ff0000;\"><strong>over object queries<\/strong><\/span>. Contrary to the latter, scalar results are not kept in the persistence context. If you run frequently some queries, consider using <a title=\"query cache\" href=\"http:\/\/docs.jboss.org\/hibernate\/core\/3.3\/reference\/en\/html\/performance.html#performance-querycache\"><strong>query cache<\/strong><\/a>.<\/li>\n<p>&nbsp;<\/p>\n<li><span style=\"color:#ff0000;\"><strong>Consider creating additional temporary<\/strong><\/span> <span style=\"color:#ff0000;\"><strong>EntityManagers<\/strong><\/span> to load specifies entities, read their value and close the temporary <strong>EntityManager<\/strong>. This <strong>EntityManager<\/strong> is completely independent and isolated from the main <strong>EntityManager<\/strong> attached to the\u00a0<strong>ThreadLocal<\/strong> in use. Look at <a href=\"http:\/\/doanduyhai.wordpress.com\/2012\/01\/14\/jpahibernate-temporary-conversations-with-spring-aop\/\" title=\"JPA\/Hibernate Temporary Conversations with Spring\u00a0AOP\" target=\"_blank\">Temporary Conversation with Spring AOP<\/a> for more details.<\/li>\n<p> &nbsp;<\/p>\n<li><span style=\"color:#ff0000;\"><strong>Consider detaching some entities when they are no longer used<\/strong><\/span>. For this, use the <em>em.detach(entityToDetach)<\/em> method. Beware of <strong>CascadeType<\/strong> configuration for collection associations in the entities candidate to be detached.<\/li>\n<p>&nbsp;<\/p>\n<li>Last but not least , <span style=\"color:#ff0000;\"><strong>find a convenient way to send the end-of-conversation signal<\/strong><\/span> to flush the persistence context and close the <strong>EntityManager<\/strong>. It is trickier than expected, especially when the signal is triggered at the Web tier and needs to be carried down to the DAO or servlet filter layer. Some available options : use another <strong>ThreadLocal<\/strong> to carry the signal (again!), use global variable,\u00a0 rely on AOP or carry a parameter along all method (brute force solution)<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h1>III Navigation models<\/h1>\n<p>As stated above, a clear navigation model for the GUI should be scketched out to help identifying entry\/exit points for the global conversation. Below we introduce two types of navigation.<\/p>\n<h2>A Generic navigation<\/h2>\n<p>This is the most common type of navigation model. There are multiple entry and exit points. Some screens act as entry point for many scenario, some others act as exit point.<\/p>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/global_navigation.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/global_navigation.png\" alt=\"\" title=\"Global_Navigation\" width=\"630\" height=\"338\" class=\"aligncenter size-full wp-image-693\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/global_navigation.png 715w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/global_navigation-300x161.png 300w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><\/a><\/p>\n<h2>B Cyclic navigation<\/h2>\n<p>In this case, there is a single screen which is the pivot point for different navigation scenarios. Each new scenario starts at the same screen so the exit point for one conversation does match with the entry point for another.<\/p>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/cyclic_navigation.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/cyclic_navigation.png\" alt=\"\" title=\"Cyclic_Navigation\" width=\"617\" height=\"482\" class=\"aligncenter size-full wp-image-694\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/cyclic_navigation.png 617w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/cyclic_navigation-300x234.png 300w\" sizes=\"(max-width: 617px) 100vw, 617px\" \/><\/a><\/p>\n<h1>III Design<\/h1>\n<h2>A Main actors<\/h2>\n<p>&nbsp;<br \/>\nThis sample implementation consists of 4 actors:<\/p>\n<ol>\n<li><strong>ConversationManager<\/strong>: the interface responsible for the management of the global conversation.<\/li>\n<li><strong>ConversationRepository<\/strong>: repository interface to store the Entity Manager for the global conversation<\/li>\n<li><strong>ConversationAnnotationProcessor<\/strong>: interface responsible for the interception of conversation demarcations<\/li>\n<li><strong>AbstractConversationFilter<\/strong>: abstract class responsible for re-attaching\/detaching the Entity Manager to the Thread Local between each request to the server<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h2>B Annotation<\/h2>\n<p>For the conversation demarcation, we introduce the following annotations:<\/p>\n<ul>\n<li><em><strong>@BeginConversation<\/strong>(entityManagerFactory=&#8221;myEntityManagerFactory1&#8243;)<\/em><\/li>\n<li><em><strong>@EndConversation<\/strong>(entityManagerFactory=&#8221;myEntityManagerFactory1&#8243;)<\/em><\/li>\n<li><em><strong>@EndCyclicConversation<\/strong>(entityManagerFactory=&#8221;myEntityManagerFactory2&#8243;)<\/em><\/li>\n<\/ul>\n<p>The first two annotations are used  by global conversations. The last one is only usefull for cyclic conversations.<br \/>\n&nbsp;<\/p>\n<h2>C ConversationManager<\/h2>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager.png\" alt=\"\" title=\"ConversationManager\" width=\"630\" height=\"163\" class=\"aligncenter size-full wp-image-695\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager.png 720w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager-300x78.png 300w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><\/a><\/p>\n<p>The <strong>ConversationManager<\/strong> interface exposes the following attributes &amp; methods:<\/p>\n<ul>\n<li><strong>repository<\/strong>: reference to a ConversationRepository instance<\/li>\n<li><strong>beginConversation(Object token, EntityManagerFactory emf)<\/strong>: start a new conversation using provided <em>emf<\/em> to create a global Entity Manager and the <em>token<\/em> to register it in the <em>repository<\/em><\/li>\n<li><strong>endConversation(Object token, EntityManagerFactory emf)<\/strong>: end a conversation. Remove the registered Entity Manager from the repository using the <em>token<\/em> as search key<\/li>\n<li><strong>reattachEntityManager(Object token, EntityManagerFactory emf)<\/strong>: look uo the global Entity Manager in the <em>repository<\/em> using the <em>token<\/em> then attach it to the Thread Local (using Spring <strong>TransactionSynchronizationManager<\/strong>)<\/li>\n<li><strong>detachEntityManager(EntityManagerFactory emf)<\/strong>: detach the global Entity Manager from the Thread Local (using Spring <strong>TransactionSynchronizationManager<\/strong>)<\/li>\n<li><strong>findEntityManager(Object token)<\/strong>: helper method to look for the Entity Manager in the <em>repository<\/em> using the <em>token<\/em><\/li>\n<li><strong>hasConversation(Object token)<\/strong>: helper method to check whether there is an on-going conversation with the <em>token<\/em> <\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h2>D ConversationRepository<\/h2>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager_conversationrepository1.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager_conversationrepository1.png\" alt=\"\" title=\"ConversationManager_ConversationRepository\" width=\"430\" height=\"439\" class=\"aligncenter size-full wp-image-697\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager_conversationrepository1.png 430w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager_conversationrepository1-294x300.png 294w\" sizes=\"(max-width: 430px) 100vw, 430px\" \/><\/a><\/p>\n<p>The <strong>ConversationRepository<\/strong> interface exposes 3 methods:<\/p>\n<ul>\n<li><strong>registerEntityManager(Object token, EntityManager em)<\/strong>: register the provided Entity Manager in the repository with <em>token<\/em> as search key<\/li>\n<li><strong>unregisterEntityManager(Object token)<\/strong>: remove the Entity Manager associated to the <em>token<\/em> from the repository<\/li>\n<li><strong>findEntityManager(Object token)<\/strong>: self-explanatory<\/li>\n<\/ul>\n<p>There are several possible implementations for this interface. The default implementation is the <strong>HttpSessionRepository<\/strong>. It uses the current user HTTP session as storage and keeps an internal map of all Entity Managers.<br \/>\n&nbsp;<\/p>\n<h2>E ConversationAnnotationProcessor<\/h2>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager_conversationannotationprocessor.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager_conversationannotationprocessor.png\" alt=\"\" title=\"ConversationManager_ConversationAnnotationProcessor\" width=\"630\" height=\"394\" class=\"aligncenter size-full wp-image-699\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager_conversationannotationprocessor.png 753w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager_conversationannotationprocessor-300x188.png 300w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><\/a><\/p>\n<p>The <strong>ConversationAnnotationProcessor<\/strong> interfaces exposes the following attributes &amp; methods:<\/p>\n<ul>\n<li><strong>conversationManager<\/strong>: reference to the ConversationManager interface<\/li>\n<li><strong>context<\/strong>: reference to the current Spring&#8217; application context<\/li>\n<li><strong>triggerBeginConversation(BeginConversation annotation)<\/strong>: intercept any method annotated with <em>@BeginConversation<\/em> and start a new conversation<\/li>\n<li><strong>triggerEndConversation(EndConversation annotation)<\/strong>: intercept any method annotated with <em>@EndConversation<\/em> and terminate the conversation<\/li>\n<li><strong>findEntityManagerFactoryInContext(String emf)<\/strong>: find the Entity Manager Factory in the Spring context using its bean id<\/li>\n<\/ul>\n<p>There are 2 possible implementations for this interface. The first one is the <strong>GlobalConversationAnnotationProcessor<\/strong>, suitable for global conversations. The second is the <strong>CyclicConversationAnnotationProcessor<\/strong> with an additional method: <em>triggerEndCyclicConversation()<\/em><\/p>\n<p>You may notice in the diagram the utility class <strong>ConversationUtils<\/strong>. This class simply helps to bind and unbind an Entity Manager to the Thread Local using Spring&#8217; <strong>TransactionSynchronizationManager<\/strong>.<\/p>\n<p>&nbsp;<\/p>\n<h2>F ConversationFilter<\/h2>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager_conversationfilter.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager_conversationfilter.png\" alt=\"\" title=\"ConversationManager_ConversationFilter\" width=\"630\" height=\"320\" class=\"aligncenter size-full wp-image-700\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager_conversationfilter.png 742w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/02\/conversationmanager_conversationfilter-300x153.png 300w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><\/a><\/p>\n<p>The <strong>AbstractConversationFilter<\/strong> class exposes the following attributes and methods:<\/p>\n<ul>\n<li><strong>conversationManager<\/strong>: reference to the <strong>Conversation Manager<\/strong><\/li>\n<li><strong>context<\/strong>: reference to the current Spring&#8217; application context<\/li>\n<li><strong>emf<\/strong>: Entity Manager Factory for the global conversation<\/li>\n<li><strong>entityManagerFactoryBeanId<\/strong>: bean id of the Entity Manager Factory in the Spring&#8217; context<\/li>\n<li><strong>setEntityManagerFactoryBeanId(String beanId)<\/strong>: setter for the <em>entityManagerFactoryBeanId<\/em> attribute<\/li>\n<li><strong>destroy()<\/strong>: called when the filter is destroyed<\/li>\n<\/ul>\n<p>Again, there are 2 implementations, <strong>GlobalConversationFilter<\/strong> &amp; <strong>CyclicConversationFilter<\/strong>. The latter redefines the <em>init()<\/em> method to start a new conversation when the filter is initialized.<\/p>\n<p>&nbsp;<\/p>\n<h1>IV Algorithm<\/h1>\n<h2>A Global conversation<\/h2>\n<ul>\n<li><u>Before the execution of any method annotated by <strong>@BeginConversation(entityManagerFactory=&#8221;emf&#8221;)<\/strong><\/u>\n<ul>\n<li><strong>ConversationAnnotationProcessor<\/strong>.<em>findEntityManagerFactoryFromContext(&#8220;emf&#8221;)<\/em><\/li>\n<li><strong>ConversationRepository<\/strong>.<em>registerEntityManager(&#8220;emf&#8221;,emf)<\/em><\/li>\n<li><strong>ConversationManager<\/strong>.<em>reattachEntityManager(&#8220;emf&#8221;,emf)<\/em><\/li>\n<\/ul>\n<\/li>\n<p>&nbsp;<\/p>\n<li><u>For each call to the <strong>ConversationFilter<\/strong><\/u>\n<ul>\n<li>If <strong>ConversationManager<\/strong>.<em>hasConversation(&#8220;entityManagerFactoryBeanId&#8221;)<\/em>\n<ul>\n<li><strong>ConversationManager<\/strong>.<em>reattachEntityManager(&#8220;entityManagerFactoryBeanId&#8221;,emf)<\/em><\/li>\n<\/ul>\n<\/li>\n<li>Continue the filter chain<\/li>\n<li><strong>ConversationManager<\/strong>.<em>detachEntityManager(emf)<\/em><\/li>\n<\/ul>\n<\/li>\n<p>&nbsp;<\/p>\n<li><u>After the execution of any method annotated by <strong>@EndConversation(entityManagerFactory=&#8221;emf&#8221;)<\/strong><\/u>\n<ul>\n<li><strong>ConversationAnnotationProcessor<\/strong>.<em>findEntityManagerFactoryFromContext(&#8220;emf&#8221;)<\/em><\/li>\n<li><strong>ConversationManager<\/strong>.<em>detachEntityManager(emf)<\/em><\/li>\n<li>Close the Entity Manager (<em>em.close()<\/em>)<\/li>\n<li><strong>ConversationRepository<\/strong>.<em>unregisterEntityManager(&#8220;emf&#8221;)<\/em><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h2>B Cyclic conversation<\/h2>\n<ul>\n<li><u>At the initialization (<em>init()<\/em>) of the <strong>ConversationFilter<\/strong><\/u>\n<ul>\n<li><strong>ConversationRepository<\/strong>.<em>registerEntityManager(&#8220;emf&#8221;,emf)<\/em><\/li>\n<li><strong>ConversationManager<\/strong>.<em>reattachEntityManager(&#8220;emf&#8221;,emf)<\/em><\/li>\n<\/ul>\n<\/li>\n<p>&nbsp;<\/p>\n<li><u>For each call to the <strong>ConversationFilter<\/strong><\/u>\n<ul>\n<li>If <strong>ConversationManager<\/strong>.<em>hasConversation(&#8220;entityManagerFactoryBeanId&#8221;)<\/em>\n<ul>\n<li><strong>ConversationManager<\/strong>.<em>reattachEntityManager(&#8220;entityManagerFactoryBeanId&#8221;,emf)<\/em><\/li>\n<\/ul>\n<\/li>\n<li>Else\n<ul>\n<li>Throw an <strong>IllegalStateException<\/strong><\/li>\n<\/ul>\n<\/li>\n<li>Continue the filter chain<\/li>\n<li><strong>ConversationManager<\/strong>.<em>detachEntityManager(emf)<\/em><\/li>\n<\/ul>\n<\/li>\n<p>&nbsp;<\/p>\n<li><u>After the execution of any method annotated by <strong>@EndCyclicConversation(entityManagerFactory=&#8221;emf&#8221;)<\/strong><\/u>\n<ul>\n<li><strong>ConversationManager<\/strong>.<em>detachEntityManager(emf)<\/em><\/li>\n<li>Close the Entity Manager (<em>em.close()<\/em>)<\/li>\n<li><strong>ConversationRepository<\/strong>.<em>unregisterEntityManager(&#8220;emf&#8221;)<\/em><\/li>\n<li><strong>ConversationRepository<\/strong>.<em>registerEntityManager(&#8220;emf&#8221;,emf)<\/em><\/li>\n<li><strong>ConversationManager<\/strong>.<em>reattachEntityManager(&#8220;emf&#8221;,emf)<\/em><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h2>C Usage<\/h2>\n<h4>1) Global conversation<\/h4>\n<pre class=\"brush: java; highlight: [3,12,21]; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\npublic class Class1\r\n{\r\n\t@BeginConversation(entityManagerFactory = &quot;myEntityManagerFactory&quot;) \r\n\tpublic void myMethod()\r\n\t{\r\n\t\t...\r\n\t}  \r\n}\r\n\r\npublic class DaoClass\r\n{\r\n\t@Transactional(value = &quot;myTransactionManager&quot;, propagation = Propagation.REQUIRED) \r\n\tpublic void save()\r\n\t{\r\n\t\t...\r\n\t}  \r\n}\r\n\r\npublic class Class2\r\n{\r\n\t@EndConversation(entityManagerFactory = &quot;myEntityManagerFactory&quot;) \r\n\tpublic void finalize()\r\n\t{\r\n\t\t...\r\n\t}  \r\n}\r\n<\/pre>\n<h4>2) Cyclic conversation<\/p>\n<pre class=\"brush: java; highlight: [3,4]; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\npublic class Class1\r\n{\r\n\t@EndCyclicConversation(entityManagerFactory = &quot;myEntityManagerFactory&quot;) \r\n\t@Transactional(value = &quot;myTransactionManager&quot;, propagation = Propagation.REQUIRED) \r\n\tpublic void endCyclicConversationMethod()\r\n\t{\r\n\t\t...\r\n\t}\r\n}\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h1>V Implementation<\/h1>\n<h2>A HttpSessionRepository<\/h2>\n<pre class=\"brush: java; highlight: [3]; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\npublic class HttpSessionRepository implements ConversationRepository\r\n{\r\n\tprivate Map&lt;Object, EntityManager&gt; conversationMap = new HashMap&lt;Object, EntityManager&gt;();\r\n\r\n\t@Override\r\n\tpublic EntityManager findEntityManager(Object token)\r\n\t{\r\n\t\treturn this.conversationMap.get(token);\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void registerEntityManager(Object token, EntityManager em)\r\n\t{\r\n\t\tthis.conversationMap.put(token, em);\r\n\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void unregisterEntityManager(Object token)\r\n\t{\r\n\t\tthis.conversationMap.remove(token);\r\n\r\n\t}\r\n\r\n\t@Override\r\n\tpublic boolean containsEntityManager(Object token)\r\n\t{\r\n\t\treturn this.conversationMap.containsKey(token);\r\n\t}\r\n}\r\n<\/pre>\n<p>Please notice that the token object is used to search for the Entity Manager in the internal Map. Consequently <strong>it should redefine the <em>equals()<\/em> &amp; <em>hashCode()<\/em> methods<\/strong>.<\/p>\n<p>&nbsp;<\/p>\n<h2>B DefaultConversationManager<\/h2>\n<pre class=\"brush: java; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\npublic class DefaultConversationManager implements ConversationManager\r\n{\r\n\r\n\tprotected ConversationRepository repository;\r\n\r\n\tprivate static final Logger logger = LoggerFactory.getLogger(DefaultConversationManager.class);\r\n\r\n\t@Override\r\n\tpublic void startConversation(Object token, EntityManagerFactory emf)\r\n\t{\r\n\t\tEntityManager em = emf.createEntityManager();\r\n\t\tthis.repository.registerEntityManager(token, em);\r\n\r\n\t\tthis.reattachEntityManager(token, emf);\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void endConversation(Object token, EntityManagerFactory emf)\r\n\t{\r\n\t\tthis.detachEntityManager(emf);\r\n\t\tEntityManager em = this.repository.findEntityManager(token);\r\n\t\tif (em != null &amp;amp;&amp;amp; em.isOpen())\r\n\t\t{\r\n\t\t\tem.close();\r\n\t\t}\r\n\t\tthis.repository.unregisterEntityManager(token);\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void reattachEntityManager(Object token, EntityManagerFactory emf)\r\n\t{\r\n\t\tif (this.repository.containsEntityManager(token))\r\n\t\t{\r\n\t\t\tEntityManager em = this.repository.findEntityManager(token);\r\n\r\n\t\t\tif (!TransactionSynchronizationManager.hasResource(emf))\r\n\t\t\t{\r\n\t\t\t\tEntityManagerHolder newEmHolder = new EntityManagerHolder(em);\r\n\t\t\t\tConversationUtils.registerResources(emf, newEmHolder);\r\n\t\t\t\tlogger.debug(&quot;Reattach the Entity Manager &quot; + em.hashCode() + &quot; to the current Thread Local&quot;);\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tthrow new IllegalStateException(&quot;There is an Entity Manager already bound to the Thread Local with the Entity Manager Factory &quot;\r\n\t\t\t\t\t\t+ emf.hashCode());\r\n\t\t\t}\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tthrow new IllegalStateException(&quot;There is no Entity Manager in the Conversation Repository with the token &quot; + token);\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void detachEntityManager(EntityManagerFactory emf)\r\n\t{\r\n\t\tif (TransactionSynchronizationManager.hasResource(emf))\r\n\t\t{\r\n\t\t\tConversationUtils.unregisterPreviousResources(emf);\r\n\t\t\tlogger.debug(&quot;Detach the Entity Manager from the current Thread Local&quot;);\r\n\t\t}\r\n\t}\r\n\r\n\t@Override\r\n\tpublic EntityManager findEntityManager(Object token)\r\n\t{\r\n\t\treturn this.repository.findEntityManager(token);\r\n\t}\r\n\r\n\t@Override\r\n\tpublic boolean hasConversation(Object token)\r\n\t{\r\n\t\treturn this.repository.containsEntityManager(token);\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void setConversationRepository(ConversationRepository repository)\r\n\t{\r\n\t\tthis.repository = repository;\r\n\r\n\t}\r\n\r\n}\r\n<\/pre>\n<p>The implementation is quite straight-forward.<br \/>\n&nbsp;<\/p>\n<h2>C Annotations<\/h2>\n<p>&nbsp;<br \/>\n<\/h4>\n<h4>1) <strong>@BeginConversation<\/strong><\/h4>\n<pre class=\"brush: java; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Target(ElementType.METHOD)\r\n@Documented\r\npublic @interface BeginConversation\r\n{\r\n\t\/**\r\n\t * &lt;p&gt;\r\n\t * Mandatory parameter. Name of the entityManagerFactory bean defined in \r\n\t * the Spring XML configuration\r\n\t * Necessary to create new Entity Manager\r\n\t * &lt;\/p&gt;\r\n\t *\/\r\n\tString entityManagerFactory();\r\n}\r\n<\/pre>\n<h4>2) <strong>@EndConversation<\/strong><\/h4>\n<pre class=\"brush: java; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Target(ElementType.METHOD)\r\n@Documented\r\npublic @interface EndConversation\r\n{\r\n\t\/**\r\n\t * &lt;p&gt;\r\n\t * Mandatory parameter. Name of the entityManagerFactory bean defined in \r\n\t * the Spring XML configuration\r\n\t * Necessary to create new Entity Manager\r\n\t * &lt;\/p&gt;\r\n\t *\/\r\n\tString entityManagerFactory();\r\n}\r\n<\/pre>\n<h4>3) <strong>@EndCyclicConversation<\/strong><\/h4>\n<pre class=\"brush: java; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Target(ElementType.METHOD)\r\n@Documented\r\npublic @interface EndCyclicConversation\r\n{\r\n\t\/**\r\n\t * &lt;p&gt;\r\n\t * Mandatory parameter. Name of the entityManagerFactory bean defined in \r\n\t * the Spring XML configuration\r\n\t * Necessary to create new Entity Manager\r\n\t * &lt;\/p&gt;\r\n\t *\/\r\n\tString entityManagerFactory();\r\n}\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h2>D GlobalConversationAnnotationProcessor<\/h2>\n<pre class=\"brush: java; highlight: [3,55]; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\n@Aspect\r\npublic class GlobalConversationAnnotationProcessor implements ConversationAnnotationProcessor, \r\nOrdered, ApplicationContextAware\r\n{\r\n\r\n\tprivate ConversationManager conversationManager;\r\n\r\n\tprivate ApplicationContext ctx;\r\n\r\n\tprivate int order;\r\n\r\n\t@Pointcut(&quot;execution(public * *(..)) &amp;amp;&amp;amp; @annotation(beginConversationAnn)&quot;)\r\n\tpublic void conversationBegin(BeginConversation beginConversationAnn)\r\n\t{}\r\n\r\n\t@Pointcut(&quot;execution(public * *(..)) &amp;amp;&amp;amp; @annotation(endConversationAnn)&quot;)\r\n\tpublic void conversationEnd(EndConversation endConversationAnn)\r\n\t{}\r\n\r\n\t@Before(&quot;conversationBegin(beginConversationAnn)&quot;)\r\n\tpublic void triggerBeginConversation(BeginConversation beginConversationAnn)\r\n\t{\r\n\t\tEntityManagerFactory emf = this.findEntityManagerFactoryFromContext(beginConversationAnn.entityManagerFactory());\r\n\t\tthis.conversationManager.startConversation(beginConversationAnn.entityManagerFactory(), emf);\r\n\t}\r\n\r\n\t@After(&quot;conversationEnd(endConversationAnn)&quot;)\r\n\tpublic void triggerEndConversation(EndConversation endConversationAnn)\r\n\t{\r\n\t\tEntityManagerFactory emf = this.findEntityManagerFactoryFromContext(endConversationAnn.entityManagerFactory());\r\n\t\tthis.conversationManager.endConversation(endConversationAnn.entityManagerFactory(), emf);\r\n\t}\r\n\r\n\t@Override\r\n\tpublic EntityManagerFactory findEntityManagerFactoryFromContext(String emf)\r\n\t{\r\n\t\treturn (EntityManagerFactory) this.ctx.getBean(emf);\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void setConversationManager(ConversationManager conversationManager)\r\n\t{\r\n\t\tthis.conversationManager = conversationManager;\r\n\r\n\t}\r\n\r\n\t@Override\r\n\tpublic int getOrder()\r\n\t{\r\n\t\treturn this.order;\r\n\t}\r\n\r\n\tpublic void setOrder(int order)\r\n\t{\r\n\t\tthis.order = order;\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException\r\n\t{\r\n\t\tthis.ctx = applicationContext;\r\n\t}\r\n<\/pre>\n<p>The <strong>GlobalConversationAnnotationProcessor<\/strong> is a Spring AOP aspect. It defines 2 pointcuts to intercept any method annotated with <strong>@BeginConversation<\/strong> or <strong>@EndConversation<\/strong> then delegates the processing to the <strong>Conversation Manager<\/strong>.<\/p>\n<p>Please notice the <strong>Ordered<\/strong> interface implemented by this class. This is important to define the order of this aspect when many aspects are applied to the same method. <\/p>\n<p>More reading about advice ordering here: <strong><a title=\"Spring advice ordering\" href=\"http:\/\/static.springsource.org\/spring\/docs\/3.0.x\/spring-framework-reference\/html\/aop.html#aop-ataspectj-advice-ordering\" target=\"_blank\">Spring advice ordering<\/a><\/strong><\/p>\n<p>Ideally this advice should be applied first and wrap all other advices.<\/p>\n<p>A simple use case of this advice ordering is when <em>@EndConversation<\/em> is used in conjunction with Spring <em>@Transactional<\/em>. The <em>@EndConversation<\/em> advice should be the first advice to kick in and the last to kick out to flush the session and close the <strong>EntityManager<\/strong>.<\/p>\n<p>&nbsp;<\/p>\n<h2>E CyclicConversationAnnotationProcessor<\/h2>\n<pre class=\"brush: java; highlight: [3,27,28]; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\n@Aspect\r\npublic class CyclicConversationAnnotationProcessor implements ConversationAnnotationProcessor, \r\nOrdered, ApplicationContextAware\r\n{\r\n\tprivate ConversationManager conversationManager;\r\n\r\n\tprivate ApplicationContext ctx;\r\n\r\n\tprivate int order;\r\n\r\n\t@Pointcut(&quot;execution(public * *(..)) &amp;amp;&amp;amp; @annotation(endCyclicConversationAnn)&quot;)\r\n\tpublic void cyclicConversationEnd(EndCyclicConversation endCyclicConversationAnn)\r\n\t{}\r\n\r\n\t@Override\r\n\tpublic void triggerBeginConversation(BeginConversation annotation)\r\n\t{}\r\n\r\n\t@Override\r\n\tpublic void triggerEndConversation(EndConversation annotation)\r\n\t{}\r\n\r\n\t@After(&quot;cyclicConversationEnd(endCyclicConversationAnn)&quot;)\r\n\tpublic void triggerEndCyclicConversation(EndCyclicConversation endCyclicConversationAnn)\r\n\t{\r\n\t\tEntityManagerFactory emf = this.findEntityManagerFactoryFromContext(endCyclicConversationAnn.entityManagerFactory());\r\n\t\tthis.conversationManager.endConversation(endCyclicConversationAnn.entityManagerFactory(), emf);\r\n\t\tthis.conversationManager.startConversation(endCyclicConversationAnn.entityManagerFactory(), emf);\r\n\t}\r\n\r\n\t@Override\r\n\tpublic EntityManagerFactory findEntityManagerFactoryFromContext(String emf)\r\n\t{\r\n\t\treturn (EntityManagerFactory) this.ctx.getBean(emf);\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void setConversationManager(ConversationManager conversationManager)\r\n\t{\r\n\t\tthis.conversationManager = conversationManager;\r\n\r\n\t}\r\n\r\n\t@Override\r\n\tpublic int getOrder()\r\n\t{\r\n\t\treturn this.order;\r\n\t}\r\n\r\n\tpublic void setOrder(int order)\r\n\t{\r\n\t\tthis.order = order;\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException\r\n\t{\r\n\t\tthis.ctx = applicationContext;\r\n\t}\r\n}\r\n<\/pre>\n<p>This implementation introduces a new method: <em>triggerEndCyclicConversation()<\/em>. What is does it simply call <strong>ConversationManager<\/strong>.<em>startConversation()<\/em> as soon as the previous conversation is finished (<strong>lines 27 &amp; 28<\/strong>)<br \/>\n&nbsp;<\/p>\n<h2>F AbstractConversationFilter<\/h2>\n<pre class=\"brush: java; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\npublic abstract class AbstractConversationFilter implements Filter, ApplicationContextAware, InitializingBean\r\n{\r\n\tprotected ConversationManager conversationManager;\r\n\r\n\tprotected ApplicationContext ctx;\r\n\r\n\tprotected EntityManagerFactory emf;\r\n\r\n\tprotected String entityManagerFactoryBeanId;\r\n\r\n\t@Override\r\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException\r\n\t{\r\n\t\tthis.ctx = applicationContext;\r\n\t}\r\n\r\n\tpublic void setEntityManagerFactoryBeanId(String emfBeanId)\r\n\t{\r\n\t\tthis.entityManagerFactoryBeanId = emfBeanId;\r\n\t}\r\n\r\n\tpublic void setConversationManager(ConversationManager conversationManager) \r\n\t{\r\n\t\tthis.conversationManager = conversationManager;\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void destroy()\r\n\t{\r\n\t\tthis.conversationManager.detachEntityManager(this.emf);\r\n\t\tthis.conversationManager.endConversation(this.entityManagerFactoryBeanId, this.emf);\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void afterPropertiesSet() throws Exception\r\n\t{\r\n\t\tif (StringUtils.isBlank(this.entityManagerFactoryBeanId))\r\n\t\t{\r\n\t\t\tthrow new ServletException(&quot;The property 'entityManagerFactoryBeanId' has not been set&quot;);\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tthis.emf = (EntityManagerFactory) this.ctx.getBean(this.entityManagerFactoryBeanId);\r\n\r\n\t\t\tif (this.emf == null)\r\n\t\t\t{\r\n\t\t\t\tthrow new IllegalStateException(&quot;The Entity Manager Factory '&quot; + this.entityManagerFactoryBeanId\r\n\t\t\t\t\t\t+ &quot;' cannot be found in the Spring context&quot;);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t}\r\n<\/pre>\n<p> The <strong>AbstractConversationFilter<\/strong> class provides a default implementation for the <em>destroy()<\/em> method. It also takes care of the initialization process through the <em>afterPropertiesSet()<\/em> method of <strong>InitializingBean<\/strong> interface.<\/p>\n<p> If the <em>entityManagerFactoryBeanId<\/em> property is empty or if the corresponding Entity Manager Factory cannot be found in the Spring context, the filter raises an exception. It offers a convenient <strong>fail-fast<\/strong> behavior.<\/p>\n<p>&nbsp;<\/p>\n<h2>G GlobalConversationFilter<\/h2>\n<pre class=\"brush: java; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\n\tprivate static final Logger logger = LoggerFactory.getLogger(GlobalConversationFilter.class);\r\n\r\n\t@Override\r\n\tpublic void init(FilterConfig arg0) throws ServletException\r\n\t{}\r\n\r\n\t@Override\r\n\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain filerChain) throws IOException, ServletException\r\n\t{\r\n\t\tif (this.conversationManager.hasConversation(this.entityManagerFactoryBeanId))\r\n\t\t{\r\n\t\t\tlogger.debug(&quot;Continuing conversation&quot;);\r\n\r\n\t\t\tthis.conversationManager.reattachEntityManager(this.entityManagerFactoryBeanId, this.emf);\r\n\t\t}\r\n\r\n\t\ttry\r\n\t\t{\r\n\t\t\tfilerChain.doFilter(request, response);\r\n\t\t}\r\n\t\tcatch (Exception ex)\r\n\t\t{\r\n\t\t\t\/\/ Exception handling\r\n\t\t}\r\n\t\tfinally\r\n\t\t{\r\n\t\t\tthis.conversationManager.detachEntityManager(this.emf);\r\n\t\t}\r\n\r\n\t}\r\n<\/pre>\n<p>The <strong>GlobalConversationFilter<\/strong> implementation is quite straight-forward. The <em>init()<\/em> method is left empty since initial checks are already done in <em>afterPropertiesSet()<\/em> of the superclass.<br \/>\n&nbsp;<\/p>\n<h2>H CyclicConversationFilter<\/h2>\n<pre class=\"brush: java; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\n\tprivate static final Logger logger = LoggerFactory.getLogger(CyclicConversationFilter.class);\r\n\r\n\t@Override\r\n\tpublic void init(FilterConfig arg0) throws ServletException\r\n\t{\r\n\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain filerChain) throws IOException, ServletException\r\n\t{\r\n\t\tboolean newConversation = this.initNewConversationIfNecessary();\r\n\r\n\t\tif (this.conversationManager.hasConversation(this.entityManagerFactoryBeanId) &amp;amp;&amp;amp; !newConversation)\r\n\t\t{\r\n\t\t\tlogger.info(&quot;Continuing conversation&quot;);\r\n\r\n\t\t\tthis.conversationManager.reattachEntityManager(this.entityManagerFactoryBeanId, this.emf);\r\n\t\t}\r\n\r\n\r\n\t\ttry\r\n\t\t{\r\n\t\t\tfilerChain.doFilter(request, response);\r\n\t\t}\r\n\t\tcatch (Exception ex)\r\n\t\t{\r\n\t\t\t\/\/ Exception handling\r\n\t\t}\r\n\t\tfinally\r\n\t\t{\r\n\t\t\tthis.conversationManager.detachEntityManager(this.emf);\r\n\t\t}\r\n\r\n\t}\r\n\t\r\n\tprivate boolean initNewConversationIfNecessary()\r\n\t{\r\n\t\tboolean newConversation = false;\r\n\t\tif (!this.conversationManager.hasConversation(this.entityManagerFactoryBeanId))\r\n\t\t{\r\n\t\t\tlogger.info(&quot;Starting new conversation&quot;);\r\n\t\t\tthis.conversationManager.startConversation(this.entityManagerFactoryBeanId, this.emf);\r\n\t\t\tnewConversation = true;\r\n\t\t}\r\n\t\t\r\n\t\treturn newConversation;\r\n\t}\r\n\r\n<\/pre>\n<p>The <strong>CyclicConversationFilter<\/strong> does redifines the <em>init()<\/em> method to start automatically a new conversation. Furthermore, <strong>an exception is raised if the filter cannot find an on-going conversation in the repository at each server request<\/strong>. Indeed with a cyclic conversation we are supposed to always have an on-going conversation.<\/p>\n<p>&nbsp;<\/p>\n<h2>I Spring configuration<\/h2>\n<pre class=\"brush: xml; highlight: [3]; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\n\r\n\t&lt;bean id=&quot;conversationRepository&quot; class=&quot;com.jpa.conversation.repository.HttpSessionRepository&quot; \r\n\t\tscope=&quot;session&quot;&gt;\r\n\t\t &lt;aop:scoped-proxy\/&gt;\r\n\t&lt;\/bean&gt;\r\n\r\n\t&lt;bean id=&quot;conversationManager&quot; class=&quot;com.jpa.conversation.manager.DefaultConversationManager&quot;&gt;\r\n\t\t&lt;property name=&quot;conversationRepository&quot; ref=&quot;conversationRepository&quot;\/&gt;\r\n\t&lt;\/bean&gt;\r\n\t\r\n\t&lt;!-- Global Conversation --&gt;\r\n\t\r\n\t&lt;bean id=&quot;conversationAnnotationProcessor&quot; class=&quot;com.jpa.conversation.annotation.processor.GlobalConversationAnnotationProcessor&quot;&gt;\r\n\t\t&lt;property name=&quot;conversationManager&quot; ref=&quot;conversationManager&quot;\/&gt;\r\n\t\t&lt;property name=&quot;order&quot; value=&quot;1&quot;\/&gt;\r\n\t&lt;\/bean&gt;\r\n\t\r\n\t&lt;bean id=&quot;conversationFilter&quot; class=&quot;com.jpa.conversation.filter.GlobalConversationFilter&quot;&gt;\r\n\t\t&lt;property name=&quot;entityManagerFactoryBeanId&quot; value=&quot;myEntityManagerFactory&quot;\/&gt;\r\n\t\t&lt;property name=&quot;conversationManager&quot; ref=&quot;conversationManager&quot;\/&gt;\r\n\t&lt;\/bean&gt;\r\n\t\r\n\t&lt;!-- Cyclic Conversation --&gt;\r\n\r\n\t&lt;bean id=&quot;conversationAnnotationProcessor&quot; class=&quot;com.jpa.conversation.annotation.processor.CyclicConversationAnnotationProcessor&quot;&gt;\r\n\t\t&lt;property name=&quot;conversationManager&quot; ref=&quot;conversationManager&quot;\/&gt;\r\n\t\t&lt;property name=&quot;order&quot; value=&quot;1&quot;\/&gt;\r\n\t&lt;\/bean&gt;\r\n\t\r\n\t&lt;bean id=&quot;conversationFilter&quot; class=&quot;com.jpa.conversation.filter.CyclicConversationFilter&quot;&gt;\r\n\t\t&lt;property name=&quot;entityManagerFactoryBeanId&quot; value=&quot;myEntityManagerFactory&quot;\/&gt;\r\n\t\t&lt;property name=&quot;conversationManager&quot; ref=&quot;conversationManager&quot;\/&gt;\r\n\t&lt;\/bean&gt;\r\n<\/pre>\n<p>Please notice the <strong><aop:scoped-proxy\/><\/strong> tag at <strong>line 3<\/strong>. It indicates that the <strong>Conversation Repository<\/strong> with <strong>session<\/strong> scope will be injected into the <strong>Conversation Manager<\/strong> which is a Spring singleton.<\/p>\n<p>Normally it does not make sense to inject a session bean into a singleton bean. The <strong><aop:scoped-proxy\/><\/strong> configuration creates a proxy which selects the appropriate instance of <strong>Conversation Repository<\/strong> for injection.<\/p>\n<p>So by defining the <strong>Conversation Repository<\/strong> with <strong>session<\/strong> scope, it is indeed unique for each user session.<\/p>\n<p>&nbsp;<\/p>\n<h2>J web.xml configuration<\/h2>\n<pre class=\"brush: xml; highlight: [5,6,9,10]; title: ; toolbar: true; wrap-lines: false; notranslate\" title=\"\">\r\n&lt;filter&gt;\r\n    \t&lt;filter-name&gt;globalConversationFilter&lt;\/filter-name&gt;\r\n    \t&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;\/filter-class&gt;\r\n   \t&lt;init-param&gt;\r\n        \t&lt;param-name&gt;targetBeanName&lt;\/param-name&gt;\r\n      \t\t&lt;param-value&gt;conversationFilter&lt;\/param-value&gt;\r\n    \t&lt;\/init-param&gt;\r\n        &lt;init-param&gt;\r\n                &lt;param-name&gt;targetFilterLifecycle&lt;\/param-name&gt;\r\n                &lt;param-value&gt;true&lt;\/param-value&gt;\r\n        &lt;\/init-param&gt;   \t\r\n&lt;\/filter&gt;\r\n...\r\n&lt;filter&gt;\r\n\t&lt;filter-name&gt;requestContextFilter&lt;\/filter-name&gt;\r\n\t&lt;filter-class&gt;org.springframework.web.filter.RequestContextFilter&lt;\/filter-class&gt;\r\n&lt;\/filter&gt;\r\n...\r\n&lt;filter-mapping&gt;\r\n    \t&lt;filter-name&gt;requestContextFilter&lt;\/filter-name&gt;\r\n    \t&lt;url-pattern&gt;\/pages\/myModule\/*&lt;\/url-pattern&gt;\r\n&lt;\/filter-mapping&gt;\r\n&lt;filter-mapping&gt;\r\n    \t&lt;filter-name&gt;globalConversationFilter&lt;\/filter-name&gt;\r\n    \t&lt;url-pattern&gt;\/pages\/myModule\/*&lt;\/url-pattern&gt;\r\n&lt;\/filter-mapping&gt;\r\n...\r\n<\/pre>\n<p>Instead of declaring the Conversation Filter directly in the web.xml file we rely on Spring DelegatingFilterProxy filter. This filter just delegates the processing to a bean in Spring context, thus allowing dependency injection.<\/p>\n<p>Pay attention to <strong>lines 5 &amp; 6<\/strong> where we indicates the id of the target bean in Spring context. It is possible to omit this information, in this case Spring will look for the bean having the id equals to the filter name (<em>globalConversationFilter<\/em>).<\/p>\n<p>At <strong>lines 9 &amp; 10<\/strong>, we set <strong>targetFilterLifecycle<\/strong> to <strong>true<\/strong> to tells Spring to propagates the servlet lifecycle to the target bean. According to the documentation, the <em>init()<\/em> &amp; <em>destroyed()<\/em> methods at the target bean are <strong>not invoked unless we activate this option<\/strong>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The previous 2 articles were dedicated to the analysis of Spring @Transactional and @PersistenceContext internals. In this article we will discuss about the JPA extended persistence context (Hibernate long session) pattern.\u00a0 We&#8217;ll look at the pros and cosn and finally&#8230;<br \/><a class=\"read-more-button\" href=\"https:\/\/www.doanduyhai.com\/blog\/?p=278\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[24,7],"tags":[34,36,40],"_links":{"self":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/278"}],"collection":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=278"}],"version-history":[{"count":3,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/278\/revisions"}],"predecessor-version":[{"id":13534,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/278\/revisions\/13534"}],"wp:attachment":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=278"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=278"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=278"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}