All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.quarkus.hibernate.orm.deployment.xml.QuarkusMappingFileParser Maven / Gradle / Ivy

package io.quarkus.hibernate.orm.deployment.xml;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import org.hibernate.boot.archive.internal.ArchiveHelper;
import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.internal.BootstrapServiceRegistryImpl;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.boot.spi.XmlMappingBinderAccess;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.integrator.spi.IntegratorService;

import io.quarkus.hibernate.orm.runtime.boot.xml.RecordableXmlMapping;
import io.quarkus.hibernate.orm.runtime.customized.QuarkusStrategySelectorBuilder;
import io.quarkus.hibernate.orm.runtime.service.FlatClassLoaderService;

/**
 * A parser for orm.xml mapping files.
 */
public final class QuarkusMappingFileParser implements AutoCloseable {

    public static QuarkusMappingFileParser create() {
        BootstrapServiceRegistry serviceRegistry = createEmptyBootstrapServiceRegistry();
        XmlMappingBinderAccess binderAccess = new XmlMappingBinderAccess(serviceRegistry);
        return new QuarkusMappingFileParser(serviceRegistry, binderAccess);
    }

    private final BootstrapServiceRegistry serviceRegistry;
    private final XmlMappingBinderAccess binderAccess;

    public QuarkusMappingFileParser(BootstrapServiceRegistry serviceRegistry, XmlMappingBinderAccess binderAccess) {
        this.serviceRegistry = serviceRegistry;
        this.binderAccess = binderAccess;
    }

    @Override
    public void close() {
        BootstrapServiceRegistryBuilder.destroy(serviceRegistry);
    }

    /**
     * @param persistenceUnitName The name of the persistence unit requesting the mapping file.
     * @param persistenceUnitRootUrl The root URL of the persistence unit requesting the mapping file.
     * @param mappingFilePath The path of the mapping file in the classpath.
     * @return A summary of the parsed mapping file, or {@link Optional#empty()} if it was not found.
     */
    public Optional parse(String persistenceUnitName, URL persistenceUnitRootUrl,
            String mappingFilePath) {
        URL url = locateMappingFile(persistenceUnitName, persistenceUnitRootUrl, mappingFilePath);

        if (url == null) {
            // Ignore and let Hibernate ORM complain about it during bootstrap.
            return Optional.empty();
        }

        try (InputStream stream = url.openStream()) {
            Binding binding = (Binding) binderAccess.bind(stream);
            return Optional.of(RecordableXmlMapping.create(binding));
        } catch (RuntimeException | IOException e) {
            throw new IllegalStateException(
                    "Error reading mapping file '" + mappingFilePath + "' ('" + url + "'): " + e.getMessage(), e);
        }
    }

    private URL locateMappingFile(String persistenceUnitName, URL persistenceUnitRootUrl, String mappingFileName) {
        List mappingFileURLs = FlatClassLoaderService.INSTANCE.locateResources(mappingFileName);
        if (mappingFileURLs.isEmpty()) {
            return null;
        } else if (mappingFileURLs.size() == 1) {
            return mappingFileURLs.get(0);
        } else { // mappingFileURLs.size() > 1
            // Multiple classpath resources match this name.
            // We need to resolve the ambiguity.
            URL urlInSameMappingFile = null;
            if (persistenceUnitRootUrl != null) {
                for (URL url : mappingFileURLs) {
                    if (!persistenceUnitRootUrl.equals(ArchiveHelper.getJarURLFromURLEntry(url, mappingFileName))) {
                        continue;
                    }
                    if (urlInSameMappingFile == null) {
                        urlInSameMappingFile = url;
                    } else {
                        // Multiple matches in the same JAR...? Can this even happen?
                        urlInSameMappingFile = null;
                        break;
                    }
                }
            }
            if (urlInSameMappingFile == null) {
                throw new IllegalStateException("Persistence unit '" + persistenceUnitName + "' references mapping file '"
                        + mappingFileName + "', but multiple resources with this path exist in the classpath,"
                        + " and it is not possible to resolve the ambiguity."
                        + " URLs of matching resources found in the classpath: " + mappingFileURLs);
            }
            return urlInSameMappingFile;
        }
    }

    private static BootstrapServiceRegistry createEmptyBootstrapServiceRegistry() {
        final ClassLoaderService providedClassLoaderService = FlatClassLoaderService.INSTANCE;
        // N.B. support for integrators removed
        final IntegratorService integratorService = new IntegratorService() {
            @Override
            public Iterable getIntegrators() {
                return Collections.emptyList();
            }
        };
        final StrategySelector strategySelector = QuarkusStrategySelectorBuilder.buildSelector(providedClassLoaderService);
        return new BootstrapServiceRegistryImpl(true, providedClassLoaderService, strategySelector, integratorService);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy