View Javadoc
1   /*
2    * Copyright (c) 2002-2022, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.util.jpa;
35  
36  import org.apache.logging.log4j.LogManager;
37  import org.apache.logging.log4j.Logger;
38  import org.springframework.dao.DataAccessResourceFailureException;
39  
40  import org.springframework.orm.jpa.EntityManagerFactoryUtils;
41  
42  import org.springframework.transaction.support.TransactionSynchronizationManager;
43  
44  import java.lang.reflect.ParameterizedType;
45  
46  import java.util.List;
47  
48  import javax.persistence.EntityManager;
49  import javax.persistence.EntityManagerFactory;
50  import javax.persistence.Query;
51  
52  /**
53   * Class JPAGenericDAO
54   * 
55   * @param <K>
56   *            Type of the entity's key
57   * @param <E>
58   *            Type of the entity
59   */
60  public abstract class JPAGenericDAO<K, E> implements IGenericDAO<K, E>
61  {
62      private static final Logger LOG = LogManager.getLogger( JPAConstants.JPA_LOGGER );
63      private Class<E> _entityClass;
64      private EntityManager _defaultEM;
65  
66      /**
67       * Constructor
68       */
69      public JPAGenericDAO( )
70      {
71          _entityClass = (Class<E>) ( (ParameterizedType) getClass( ).getGenericSuperclass( ) ).getActualTypeArguments( ) [1];
72      }
73  
74      /**
75       * Inherit classes should provide their Entity Manager Factory
76       * 
77       * @return The Entity Manager Factory that will create Entity Manager for this DAO
78       */
79      public abstract EntityManagerFactory getEntityManagerFactory( );
80  
81      /**
82       * Returns the entity class name
83       * 
84       * @return The entity class name
85       */
86      public String getEntityClassName( )
87      {
88          return _entityClass.getName( );
89      }
90  
91      /**
92       * Gets the entity class
93       * 
94       * @return the entity class
95       */
96      public Class<E> getEntityClass( )
97      {
98          return _entityClass;
99      }
100 
101     /**
102      * Return the Entity Manager
103      * 
104      * @return The Entity Manager
105      */
106     public EntityManager getEM( )
107     {
108         EntityManagerFactory emf = getEntityManagerFactory( );
109 
110         if ( TransactionSynchronizationManager.isSynchronizationActive( ) )
111         {
112             // first, get Spring entitymanager (if available)
113             try
114             {
115                 EntityManager em = EntityManagerFactoryUtils.getTransactionalEntityManager( emf );
116 
117                 if ( em == null )
118                 {
119                     LOG.error( "getEM(  ) : no EntityManager found. Will use native entity manager factory [Transaction will not be supported]" );
120                 }
121                 else
122                 {
123                     LOG.debug( "EntityManager found for the current transaction : {}  - using Factory :  {}", em::toString, emf::toString );
124 
125                     return em;
126                 }
127             }
128             catch( DataAccessResourceFailureException ex )
129             {
130                 LOG.error( ex );
131             }
132         }
133 
134         LOG.error( "getEM(  ) : no EntityManager found. Will use native entity manager factory [Transaction will not be supported]" );
135 
136         if ( _defaultEM == null )
137         {
138             _defaultEM = emf.createEntityManager( );
139         }
140         return _defaultEM;
141     }
142 
143     /**
144      * {@inheritDoc }
145      */
146     @Override
147     public void create( E entity )
148     {
149         LOG.debug( "Creating entity : {}", entity::toString );
150 
151         EntityManager em = getEM( );
152 
153         if ( em == _defaultEM )
154         {
155             em.getTransaction( ).begin( );
156         }
157         em.persist( entity );
158         if ( em == _defaultEM )
159         {
160             em.getTransaction( ).commit( );
161         }
162 
163         LOG.debug( "Entity created : {}", entity::toString );
164     }
165 
166     /**
167      * {@inheritDoc }
168      */
169     @Override
170     public void remove( K key )
171     {
172         EntityManager em = getEM( );
173         E entity = em.find( _entityClass, key );
174         if ( entity == null )
175         {
176             LOG.debug( "Did not find entity to remove for key {} ", key::toString );
177             return;
178         }
179         LOG.debug( "Removing entity : {}", entity::toString );
180         if ( em == _defaultEM )
181         {
182             em.getTransaction( ).begin( );
183         }
184         em.remove( entity );
185         if ( em == _defaultEM )
186         {
187             em.getTransaction( ).commit( );
188         }
189         LOG.debug( "Entity removed : {}", entity::toString );
190     }
191 
192     /**
193      * {@inheritDoc }
194      */
195     @Override
196     public void update( E entity )
197     {
198         LOG.debug( "Updating entity : {}", entity::toString );
199 
200         EntityManager em = getEM( );
201         if ( em == _defaultEM )
202         {
203             em.getTransaction( ).begin( );
204         }
205         em.merge( entity );
206         if ( em == _defaultEM )
207         {
208             em.getTransaction( ).commit( );
209         }
210 
211         LOG.debug( "Entity Updated : {}", entity::toString );
212     }
213 
214     /**
215      * {@inheritDoc }
216      */
217     @Override
218     public E findById( K key )
219     {
220         LOG.debug( "Selecting entity {} by Id ", ( ) -> getEntityClassName( ), key::toString );
221 
222         return getEM( ).find( _entityClass, key );
223     }
224 
225     /**
226      * {@inheritDoc }
227      */
228     @Override
229     public List<E> findAll( )
230     {
231         LOG.debug( "Selecting all entities of type : {}", ( ) -> getEntityClassName( ) );
232 
233         Query query = getEM( ).createQuery( "SELECT e FROM " + getEntityClassName( ) + " e " );
234 
235         return query.getResultList( );
236     }
237 
238     /**
239      *
240      * {@inheritDoc}
241      */
242     @Override
243     public void flush( )
244     {
245         getEM( ).flush( );
246     }
247 
248     /**
249      *
250      * {@inheritDoc}
251      */
252     @Override
253     public void detach( E entity )
254     {
255         getEM( ).detach( entity );
256     }
257 }