Skip to content

Instantly share code, notes, and snippets.

@baumato
Last active December 21, 2020 09:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save baumato/3283f255b00094411110fc889be58aa5 to your computer and use it in GitHub Desktop.
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.
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);
}
}
}
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