6060import java .util .stream .Collectors ;
6161import javax .xml .parsers .DocumentBuilder ;
6262import javax .xml .parsers .DocumentBuilderFactory ;
63+ import javax .xml .parsers .ParserConfigurationException ;
6364import javax .xml .xpath .XPath ;
6465import javax .xml .xpath .XPathConstants ;
66+ import javax .xml .xpath .XPathExpressionException ;
6567import javax .xml .xpath .XPathFactory ;
6668import org .jetbrains .annotations .NotNull ;
6769import org .jetbrains .annotations .Nullable ;
70+ import org .jetbrains .annotations .TestOnly ;
6871import org .slf4j .Logger ;
6972import org .slf4j .LoggerFactory ;
7073import org .w3c .dom .Document ;
@@ -80,7 +83,7 @@ public class PolarisEclipseLinkMetaStoreSessionImpl implements PolarisMetaStoreS
8083 private static final Logger LOG =
8184 LoggerFactory .getLogger (PolarisEclipseLinkMetaStoreSessionImpl .class );
8285
83- private final EntityManagerFactory emf ;
86+ private static volatile EntityManagerFactory emf ;
8487 private final ThreadLocal <EntityManager > localSession = new ThreadLocal <>();
8588 private final PolarisEclipseLinkStore store ;
8689 private final PolarisStorageIntegrationProvider storageIntegrationProvider ;
@@ -100,20 +103,28 @@ public PolarisEclipseLinkMetaStoreSessionImpl(
100103 @ NotNull RealmContext realmContext ,
101104 @ Nullable String confFile ,
102105 @ Nullable String persistenceUnitName ) {
103-
104- emf = createEntityManagerFactory (realmContext , confFile , persistenceUnitName );
105106 LOG .debug ("Create EclipseLink Meta Store Session for {}" , realmContext .getRealmIdentifier ());
107+ emf = createEntityManagerFactory (realmContext , confFile , persistenceUnitName );
106108
107109 // init store
108110 this .store = store ;
109111 this .storageIntegrationProvider = storageIntegrationProvider ;
110112 }
111113
112- /** Load the persistence unit properties from a given configuration file */
114+ /**
115+ * Create EntityManagerFactory.
116+ *
117+ * <p>The creation is expensive, but it should only need to create once and can be reused across
118+ * the sessions.
119+ */
113120 private EntityManagerFactory createEntityManagerFactory (
114121 @ NotNull RealmContext realmContext ,
115122 @ Nullable String confFile ,
116123 @ Nullable String persistenceUnitName ) {
124+ if (emf != null ) {
125+ return emf ;
126+ }
127+
117128 ClassLoader prevClassLoader = Thread .currentThread ().getContextClassLoader ();
118129 try {
119130 persistenceUnitName = persistenceUnitName == null ? "polaris" : persistenceUnitName ;
@@ -131,8 +142,15 @@ private EntityManagerFactory createEntityManagerFactory(
131142 if (prefixUrl == null ) {
132143 prefixUrl = new File (jarPrefixPath ).toURI ().toURL ();
133144 }
145+
146+ LOG .info (
147+ "Created a new ClassLoader with the jar {} in classpath to load the config file" ,
148+ prefixUrl );
149+
134150 URLClassLoader currentClassLoader =
135151 new URLClassLoader (new URL [] {prefixUrl }, this .getClass ().getClassLoader ());
152+
153+ LOG .debug ("Update ClassLoader in current thread temporarily" );
136154 Thread .currentThread ().setContextClassLoader (currentClassLoader );
137155 }
138156
@@ -146,16 +164,24 @@ private EntityManagerFactory createEntityManagerFactory(
146164 properties .put (ECLIPSELINK_PERSISTENCE_XML , confFile );
147165
148166 return Persistence .createEntityManagerFactory (persistenceUnitName , properties );
149- } catch (Exception e ) {
167+ } catch (IOException e ) {
150168 throw new RuntimeException (e );
151169 } finally {
152170 Thread .currentThread ().setContextClassLoader (prevClassLoader );
153171 }
154172 }
155173
174+ @ TestOnly
175+ static void clearEntityManagerFactory () {
176+ if (emf != null ) {
177+ emf .close ();
178+ emf = null ;
179+ }
180+ }
181+
156182 /** Load the persistence unit properties from a given configuration file */
157183 private Map <String , String > loadProperties (
158- @ NotNull String confFile , @ NotNull String persistenceUnitName ) throws Exception {
184+ @ NotNull String confFile , @ NotNull String persistenceUnitName ) throws IOException {
159185 try {
160186 InputStream input =
161187 Thread .currentThread ().getContextClassLoader ().getResourceAsStream (confFile );
@@ -176,13 +202,16 @@ private Map<String, String> loadProperties(
176202 }
177203
178204 return properties ;
179- } catch (SAXException | IOException e ) {
205+ } catch (XPathExpressionException
206+ | ParserConfigurationException
207+ | SAXException
208+ | IOException e ) {
180209 String str =
181210 String .format (
182211 "Cannot find or parse the configuration file %s for persistence-unit %s" ,
183212 confFile , persistenceUnitName );
184- LOG .error (str );
185- throw new Exception (str );
213+ LOG .error (str , e );
214+ throw new IOException (str );
186215 }
187216 }
188217
0 commit comments