Skip to content

Commit

Permalink
Support external config file for eclipselink
Browse files Browse the repository at this point in the history
    Due to the limitation of eclipselink, the config file has to be a resource inside a jar so a config file like /tmp/persistence.xml can't be supported directly.
    To workaround the issue,
    1. create a jar file from persistence.xml through 'jar /tmp/cf conf.jar ./persistence.xml'
    3. configure eclipselink in polaris-server.yml
           metaStoreManager:
             type: eclipse-link
             persistence-unit: polaris
             conf-file: /tmp/conf.jar!/persistence.xml
  • Loading branch information
aihuaxu committed Aug 6, 2024
1 parent 353acea commit 023bb41
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 30 deletions.
8 changes: 8 additions & 0 deletions extension/persistence/eclipselink/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,12 @@ dependencies {

testImplementation(libs.h2)
testImplementation(testFixtures(project(":polaris-core")))

sourceSets {
test {
resources {
srcDir 'src/test/data'
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import static org.eclipse.persistence.config.PersistenceUnitProperties.JDBC_URL;

import com.google.common.base.Predicates;
import com.google.common.collect.Maps;
import io.polaris.core.PolarisCallContext;
import io.polaris.core.context.RealmContext;
import io.polaris.core.entity.PolarisBaseEntity;
Expand Down Expand Up @@ -47,7 +46,11 @@
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.OptimisticLockException;
import jakarta.persistence.Persistence;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -67,6 +70,7 @@
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
* EclipseLink implementation of a Polaris metadata store supporting persisting and retrieving all
Expand All @@ -80,7 +84,6 @@ public class PolarisEclipseLinkMetaStoreSessionImpl implements PolarisMetaStoreS
private final ThreadLocal<EntityManager> localSession = new ThreadLocal<>();
private final PolarisEclipseLinkStore store;
private final PolarisStorageIntegrationProvider storageIntegrationProvider;
private static volatile Map<String, String> properties;

/**
* Create a meta store session against provided realm. Each realm has its own database.
Expand All @@ -97,19 +100,8 @@ public PolarisEclipseLinkMetaStoreSessionImpl(
@NotNull RealmContext realmContext,
@Nullable String confFile,
@Nullable String persistenceUnitName) {
persistenceUnitName = persistenceUnitName == null ? "polaris" : persistenceUnitName;
Map<String, String> properties =
loadProperties(
confFile == null ? "META-INF/persistence.xml" : confFile, persistenceUnitName);
// Replace database name in JDBC URL with realm
if (properties.containsKey(JDBC_URL)) {
properties.put(
JDBC_URL, properties.get(JDBC_URL).replace("{realm}", realmContext.getRealmIdentifier()));
}
properties.put(ECLIPSELINK_PERSISTENCE_XML, confFile);

emf = Persistence.createEntityManagerFactory(persistenceUnitName, properties);

emf = createEntityManagerFactory(realmContext, confFile, persistenceUnitName);
LOG.debug("Create EclipseLink Meta Store Session for {}", realmContext.getRealmIdentifier());

// init store
Expand All @@ -118,13 +110,55 @@ public PolarisEclipseLinkMetaStoreSessionImpl(
}

/** Load the persistence unit properties from a given configuration file */
private Map<String, String> loadProperties(String confFile, String persistenceUnitName) {
if (properties != null) {
return properties;
private EntityManagerFactory createEntityManagerFactory(
@NotNull RealmContext realmContext,
@Nullable String confFile,
@Nullable String persistenceUnitName) {
ClassLoader prevClassLoader = Thread.currentThread().getContextClassLoader();
try {
persistenceUnitName = persistenceUnitName == null ? "polaris" : persistenceUnitName;
confFile = confFile == null ? "META-INF/persistence.xml" : confFile;

// Currently eclipseLink can only support configuration as a resource inside a jar. To support
// external configuration, persistence.xml needs be placed inside a jar and here is to add the
// jar to the classpath.
// Supported configuration file: META-INFO/persistence.xml, /tmp/conf.jar!/persistence.xml
int splitPosition = confFile.indexOf("!/");
if (splitPosition != -1) {
String jarPrefixPath = confFile.substring(0, splitPosition);
confFile = confFile.substring(splitPosition + 2);
URL prefixUrl = this.getClass().getClassLoader().getResource(jarPrefixPath);
if (prefixUrl == null) {
prefixUrl = new File(jarPrefixPath).toURI().toURL();
}
URLClassLoader currentClassLoader =
new URLClassLoader(new URL[] {prefixUrl}, this.getClass().getClassLoader());
Thread.currentThread().setContextClassLoader(currentClassLoader);
}

Map<String, String> properties = loadProperties(confFile, persistenceUnitName);
// Replace database name in JDBC URL with realm
if (properties.containsKey(JDBC_URL)) {
properties.put(
JDBC_URL,
properties.get(JDBC_URL).replace("{realm}", realmContext.getRealmIdentifier()));
}
properties.put(ECLIPSELINK_PERSISTENCE_XML, confFile);

return Persistence.createEntityManagerFactory(persistenceUnitName, properties);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
Thread.currentThread().setContextClassLoader(prevClassLoader);
}
}

/** Load the persistence unit properties from a given configuration file */
private Map<String, String> loadProperties(
@NotNull String confFile, @NotNull String persistenceUnitName) throws Exception {
try {
InputStream input = this.getClass().getClassLoader().getResourceAsStream(confFile);
InputStream input =
Thread.currentThread().getContextClassLoader().getResourceAsStream(confFile);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(input);
Expand All @@ -141,16 +175,15 @@ private Map<String, String> loadProperties(String confFile, String persistenceUn
nodeMap.getNamedItem("value").getNodeValue());
}

PolarisEclipseLinkMetaStoreSessionImpl.properties = properties;
return properties;
} catch (Exception e) {
LOG.warn(
"Cannot find or parse the configuration file {} for persistence-unit {}",
confFile,
persistenceUnitName);
} catch (SAXException | IOException e) {
String str =
String.format(
"Cannot find or parse the configuration file %s for persistence-unit %s",
confFile, persistenceUnitName);
LOG.error(str);
throw new Exception(str);
}

return Maps.newHashMap();
}

/** {@inheritDoc} */
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
*/
package com.snowflake.polaris.persistence.impl.eclipselink;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import io.polaris.core.PolarisCallContext;
import io.polaris.core.PolarisConfigurationStore;
import io.polaris.core.PolarisDefaultDiagServiceImpl;
Expand All @@ -25,6 +29,12 @@
import io.polaris.extension.persistence.impl.eclipselink.PolarisEclipseLinkMetaStoreSessionImpl;
import io.polaris.extension.persistence.impl.eclipselink.PolarisEclipseLinkStore;
import java.time.ZoneId;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.provider.ArgumentsSource;
import org.mockito.Mockito;

/**
Expand All @@ -49,4 +59,30 @@ protected PolarisTestMetaStoreManager createPolarisTestMetaStoreManager() {
new PolarisConfigurationStore() {},
timeSource.withZone(ZoneId.systemDefault())));
}

@ParameterizedTest()
@ArgumentsSource(CreateStoreSessionArgs.class)
void testCreateStoreSession(String confFile, boolean success) {
PolarisDiagnostics diagServices = new PolarisDefaultDiagServiceImpl();
PolarisEclipseLinkStore store = new PolarisEclipseLinkStore(diagServices);
try {
var session =
new PolarisEclipseLinkMetaStoreSessionImpl(
store, Mockito.mock(), () -> "realm", confFile, "polaris-dev");
assertNotNull(session);
assertTrue(success);
} catch (Exception e) {
assertFalse(success);
}
}

private static class CreateStoreSessionArgs implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) {
return Stream.of(
Arguments.of("META-INF/persistence.xml", true),
Arguments.of("eclipselink_conf.jar!/persistence.xml", true),
Arguments.of("/dummy_path/conf.jar!/persistence.xml", false));
}
}
}
3 changes: 2 additions & 1 deletion polaris-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ defaultRealms:
metaStoreManager:
type: in-memory
# type: eclipse-link # uncomment to use eclipse-link as metastore
# persistence-unit: polaris-dev
# persistence-unit: polaris


# TODO - avoid duplicating token broker config
oauth2:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,5 @@
# limitations under the License.
#

io.polaris.extension.persistence.impl.hibernate.HibernatePolarisMetaStoreManagerFactory
io.polaris.service.persistence.InMemoryPolarisMetaStoreManagerFactory
com.snowflake.polaris.persistence.impl.remote.RemotePolarisMetaStoreManagerFactory
io.polaris.extension.persistence.impl.eclipselink.EclipseLinkPolarisMetaStoreManagerFactory
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

<persistence-unit name="polaris" transaction-type="RESOURCE_LOCAL">
<persistence-unit name="polaris-dev" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>io.polaris.core.persistence.models.ModelEntity</class>
<class>io.polaris.core.persistence.models.ModelEntityActive</class>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ metaStoreManager:
type: in-memory
# type: remote
# url: http://sdp-devvm-mcollado:8080
# type: eclipse-link # uncomment to use eclipse-link as metastore
# persistence-unit: polaris-dev

oauth2:
type: default
Expand Down

0 comments on commit 023bb41

Please sign in to comment.