ExternalServerPersistenceContext.java
/*******************************************************************************
* Copyright (c) 2026 Carsten Hammer and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.jgit.server.config;
import java.util.Objects;
import java.util.Properties;
import org.eclipse.jgit.server.repository.ExternalHibernateRepositoryService;
import org.eclipse.jgit.server.repository.SandboxRepositoryService;
import org.hibernate.SessionFactory;
import org.sandbox.jgit.storage.integration.SandboxProjectionEntities;
import io.github.carstenartur.jgit.storage.hibernate.DefaultHibernateRepositoryFactory;
import io.github.carstenartur.jgit.storage.hibernate.config.HibernateSessionFactoryProvider;
/**
* Application-owned persistence context backed by the released generic Core
* implementation.
*
* <p>This context is intentionally not the normal server default yet. It
* registers the released Core mappings exactly once together with the explicit
* compatible Sandbox projection list. Production construction must go through
* {@link HibernateConfig#createExternalPersistenceContext(Properties)}, which
* verifies the Flyway history and Hibernate validation mode before bootstrap.</p>
*/
final class ExternalServerPersistenceContext implements ServerPersistenceContext {
private static final String LUCENE= "lucene"; //$NON-NLS-1$
private static final String LOCAL_FILESYSTEM= "local-filesystem"; //$NON-NLS-1$
private final HibernateSessionFactoryProvider owner;
private final SandboxRepositoryService repositories;
ExternalServerPersistenceContext(Properties properties) {
this(new HibernateSessionFactoryProvider(
serverProperties(Objects.requireNonNull(properties, "properties")), //$NON-NLS-1$
SandboxProjectionEntities.annotatedClasses()));
}
ExternalServerPersistenceContext(HibernateSessionFactoryProvider owner) {
this.owner= Objects.requireNonNull(owner, "owner"); //$NON-NLS-1$
this.repositories= new ExternalHibernateRepositoryService(
new DefaultHibernateRepositoryFactory(owner.getSessionFactory()));
}
@Override
public SessionFactory sessionFactory() {
return owner.getSessionFactory();
}
@Override
public SandboxRepositoryService repositoryService() {
return repositories;
}
@Override
public void close() {
RuntimeException failure= null;
try {
repositories.close();
} catch (RuntimeException exception) {
failure= exception;
}
try {
owner.close();
} catch (RuntimeException exception) {
if (failure == null) {
failure= exception;
} else {
failure.addSuppressed(exception);
}
}
if (failure != null) {
throw failure;
}
}
private static Properties serverProperties(Properties properties) {
Properties copy= new Properties();
copy.putAll(properties);
copy.putIfAbsent("hibernate.search.backend.type", LUCENE); //$NON-NLS-1$
String backend= copy.getProperty("hibernate.search.backend.type"); //$NON-NLS-1$
if (LUCENE.equalsIgnoreCase(backend)) {
copy.putIfAbsent("hibernate.search.backend.directory.type", //$NON-NLS-1$
LOCAL_FILESYSTEM);
if (LOCAL_FILESYSTEM.equalsIgnoreCase(copy.getProperty(
"hibernate.search.backend.directory.type"))) { //$NON-NLS-1$
String root= System.getenv("JGIT_SEARCH_INDEX_DIR"); //$NON-NLS-1$
if (root == null || root.isBlank()) {
root= "jgit-search-index"; //$NON-NLS-1$
}
copy.putIfAbsent("hibernate.search.backend.directory.root", root); //$NON-NLS-1$
}
}
copy.putIfAbsent("hibernate.search.backend.analysis.configurer", //$NON-NLS-1$
"class:org.eclipse.jgit.storage.hibernate.search.JavaSourceAnalysisConfigurer"); //$NON-NLS-1$
copy.putIfAbsent("hibernate.connection.provider_class", //$NON-NLS-1$
"org.hibernate.hikaricp.internal.HikariCPConnectionProvider"); //$NON-NLS-1$
copy.putIfAbsent("hibernate.hikari.minimumIdle", "5"); //$NON-NLS-1$ //$NON-NLS-2$
copy.putIfAbsent("hibernate.hikari.maximumPoolSize", "20"); //$NON-NLS-1$ //$NON-NLS-2$
copy.putIfAbsent("hibernate.hikari.idleTimeout", "300000"); //$NON-NLS-1$ //$NON-NLS-2$
copy.putIfAbsent("hibernate.hikari.connectionTimeout", "20000"); //$NON-NLS-1$ //$NON-NLS-2$
copy.putIfAbsent("hibernate.hikari.maxLifetime", "1200000"); //$NON-NLS-1$ //$NON-NLS-2$
copy.putIfAbsent("hibernate.connection.handling_mode", //$NON-NLS-1$
"DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION"); //$NON-NLS-1$
copy.putIfAbsent("hibernate.cache.use_second_level_cache", "true"); //$NON-NLS-1$ //$NON-NLS-2$
copy.putIfAbsent("hibernate.cache.region.factory_class", "jcache"); //$NON-NLS-1$ //$NON-NLS-2$
return copy;
}
}