Last active
February 19, 2025 12:12
-
-
Save baumato/3283f255b00094411110fc889be58aa5 to your computer and use it in GitHub Desktop.
When working with eclipseLink as JPA provider then the EnvironmentalEntityManagerFactory allows to use environment variables in the persistence.xml. This factory should be used instead of Persistence.createEntityManagerFactory.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.hlag.fis.test.persistence; | |
import java.util.Collections; | |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.Map.Entry; | |
import java.util.Properties; | |
import javax.persistence.EntityManager; | |
import javax.persistence.EntityManagerFactory; | |
import javax.persistence.Persistence; | |
import javax.persistence.spi.PersistenceUnitInfo; | |
import org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate; | |
import org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl; | |
import com.google.common.collect.Maps; | |
/** | |
* Use this class instead of | |
* | |
* <pre> | |
* <code> | |
* EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(puName); | |
* EntityManager em = entityManagerFactory.createEntityManager(); | |
* </code> | |
* </pre> | |
* | |
* because this class allows to override properties using environment variables. Usage in persistence.xml: | |
* | |
* <pre> | |
* <code> | |
* <property name="javax.persistence.jdbc.url" | |
* value="jdbc:db2://${DEVE_DB_HOST}/DB:currentSchema=DEVELOP;" /> | |
* <property name="javax.persistence.jdbc.user" value="${DEVE_DB_USER}" /> | |
* <property name="javax.persistence.jdbc.password" value="${DEVE_DB_PASSWORD}" /> | |
* </code> | |
* </pre> | |
*/ | |
public class EnvironmentalEntityManagerFactory { | |
private static final Map<String, String> ENVIRONMENT = new HashMap<>(System.getenv()); | |
public static void setEnvironmentVariables(Map<String, String> environment) { | |
ENVIRONMENT.putAll(environment); | |
} | |
public static void resetEnvironmentVariables() { | |
ENVIRONMENT.clear(); | |
ENVIRONMENT.putAll(System.getenv()); | |
} | |
public static EntityManager createEntityManager(String persistenceUnitName) { | |
return createEntityManager(persistenceUnitName, Collections.emptyMap()); | |
} | |
public static EntityManager createEntityManager( | |
String persistenceUnitName, | |
Map<Object, Object> entityManagerFactoryProperties) { | |
return createEntityManagerFactory(persistenceUnitName, entityManagerFactoryProperties).createEntityManager(); | |
} | |
public static EntityManagerFactory createEntityManagerFactory( | |
String persistenceUnitName, | |
Map<Object, Object> properties) { | |
EntityManagerFactory factory = Persistence.createEntityManagerFactory(persistenceUnitName); | |
try (ClosableEntityManagerFactoryProperties factoryProps = new ClosableEntityManagerFactoryProperties(factory)) { | |
Map<Object, Object> overrideProps = replaceWithEnvironmentVariableValues(factoryProps.asMap()); | |
overrideProps.putAll(properties); | |
return Persistence.createEntityManagerFactory(persistenceUnitName, overrideProps); | |
} | |
} | |
private static Map<Object, Object> replaceWithEnvironmentVariableValues(Map<String, String> props) { | |
Map<Object, Object> overrideProps = new HashMap<>(); | |
for (Entry<String, String> entry : props.entrySet()) { | |
String key = entry.getKey(); | |
String value = entry.getValue(); | |
boolean overridden = false; | |
if (containsVariable(key)) { | |
key = replaceWithVariableValue(key); | |
overridden = true; | |
} | |
if (containsVariable(value)) { | |
value = replaceWithVariableValue(value); | |
overridden = true; | |
} | |
if (overridden) { | |
overrideProps.put(key, value); | |
} | |
} | |
return overrideProps; | |
} | |
private static boolean containsVariable(String s) { | |
int variableStartIndex = s.indexOf("${"); | |
int variableEndIndex = s.lastIndexOf('}'); | |
return variableStartIndex >= 0 && variableStartIndex < variableEndIndex; | |
} | |
private static String replaceWithVariableValue(String key) { | |
for (Entry<String, String> entry : ENVIRONMENT.entrySet()) { | |
key = key.replace("${" + entry.getKey() + "}", entry.getValue()); | |
} | |
return key; | |
} | |
static final class ClosableEntityManagerFactoryProperties implements AutoCloseable { | |
private final EntityManagerFactory factory; | |
ClosableEntityManagerFactoryProperties(EntityManagerFactory factory) { | |
this.factory = factory; | |
} | |
@Override | |
public void close() { | |
factory.close(); | |
} | |
Map<String, String> asMap() { | |
EntityManagerFactoryImpl eclipseLinkFactory = factory.unwrap(EntityManagerFactoryImpl.class); | |
EntityManagerFactoryDelegate delegate = eclipseLinkFactory.unwrap(EntityManagerFactoryDelegate.class); | |
PersistenceUnitInfo persistenceUnitInfo = delegate.getSetupImpl().getPersistenceUnitInfo(); | |
Properties factoryProps = persistenceUnitInfo.getProperties(); | |
return Maps.fromProperties(factoryProps); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.hlag.fis.test.persistence; | |
import static org.assertj.core.api.Assertions.assertThat; | |
import java.util.Collections; | |
import javax.persistence.EntityManagerFactory; | |
import org.junit.Rule; | |
import org.junit.Test; | |
import org.junit.rules.ExternalResource; | |
import com.google.common.collect.ImmutableMap; | |
import com.hlag.fis.test.persistence.EnvironmentalEntityManagerFactory.ClosableEntityManagerFactoryProperties; | |
public class EnvironmentalEntityManagerFactoryUnitTest { | |
private static final String PERSISTENCE_UNIT = "environmentalPersistenceUnit"; | |
@Rule | |
public EnvironmentalEntityManagerFactoryRule environment = new EnvironmentalEntityManagerFactoryRule(); | |
@Test | |
public void shouldReplaceVariablesInPersistenceXml_whenCreatingEntityManagerFactory_givenEnvironmentVariables() { | |
environment.put("DEVE_DB_HOST", "DB2_URL"); | |
EntityManagerFactory factory = EnvironmentalEntityManagerFactory | |
.createEntityManagerFactory(PERSISTENCE_UNIT, Collections.emptyMap()); | |
try (ClosableEntityManagerFactoryProperties closebleFactory = new ClosableEntityManagerFactoryProperties(factory)) { | |
String jdbcUrl = String.valueOf(factory.getProperties().get("javax.persistence.jdbc.url")); | |
assertThat(jdbcUrl).contains("jdbc:db2://DB2_URL/"); | |
} | |
} | |
@Test | |
public void shouldSupportPropertiesFromOutside_whenCreatingEntityManagerFactory_givenPropertiesFromOutside() { | |
Object value = new Object(); | |
EntityManagerFactory factory = EnvironmentalEntityManagerFactory | |
.createEntityManagerFactory(PERSISTENCE_UNIT, ImmutableMap.of("KEY", value)); | |
try (ClosableEntityManagerFactoryProperties closebleFactory = new ClosableEntityManagerFactoryProperties(factory)) { | |
Object actual = factory.getProperties().get("KEY"); | |
assertThat(actual).isEqualTo(value); | |
} | |
} | |
@Test | |
public void shouldSupportMultipleVariablesInOneProperty_whenCreatingEntityManagerFactory_givenPersistenceXmlPropertyWithMultipleVariables() { | |
environment.put("FIRST", "1"); | |
environment.put("SECOND", "2"); | |
EntityManagerFactory factory = EnvironmentalEntityManagerFactory | |
.createEntityManagerFactory(PERSISTENCE_UNIT, Collections.emptyMap()); | |
try (ClosableEntityManagerFactoryProperties closebleFactory = new ClosableEntityManagerFactoryProperties(factory)) { | |
String actual = String.valueOf(factory.getProperties().get("multiple_variables")); | |
assertThat(actual).isEqualTo("first 1 second 2 third ..."); | |
} | |
} | |
private static class EnvironmentalEntityManagerFactoryRule extends ExternalResource { | |
@Override | |
protected void before() throws Throwable { | |
} | |
void put(String key, String value) { | |
EnvironmentalEntityManagerFactory.setEnvironmentVariables(ImmutableMap.of(key, value)); | |
} | |
@Override | |
protected void after() { | |
EnvironmentalEntityManagerFactory.resetEnvironmentVariables(); | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment