From 7e87bb0a0fbe438f2fc03b69f829cae29019f999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 2 Aug 2021 12:50:29 +0200 Subject: [PATCH] Push Hibernate ORM DevConsole info on startup instead of pulling it at runtime --- .../orm/deployment/HibernateOrmProcessor.java | 7 +- .../devconsole/DevConsoleProcessor.java | 4 +- .../dev-templates/persistence-units.html | 4 +- .../FastBootHibernatePersistenceProvider.java | 23 ----- .../orm/runtime/PersistenceUnitsHolder.java | 9 +- .../FastBootEntityManagerFactoryBuilder.java | 44 ---------- .../PreconfiguredServiceRegistryBuilder.java | 8 +- ...> HibernateOrmDevConsoleInfoSupplier.java} | 85 ++++++++++++------- .../HibernateOrmDevConsoleIntegrator.java | 23 +++++ 9 files changed, 87 insertions(+), 120 deletions(-) rename extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/{PersistenceUnitInfoSupplier.java => HibernateOrmDevConsoleInfoSupplier.java} (54%) create mode 100644 extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/HibernateOrmDevConsoleIntegrator.java diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java index 0c6789b669b03c..7dd7c391e24dc9 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java @@ -118,6 +118,7 @@ import io.quarkus.hibernate.orm.runtime.boot.scan.QuarkusScanner; import io.quarkus.hibernate.orm.runtime.boot.xml.RecordableXmlMapping; import io.quarkus.hibernate.orm.runtime.cdi.QuarkusArcBeanContainer; +import io.quarkus.hibernate.orm.runtime.devconsole.HibernateOrmDevConsoleIntegrator; import io.quarkus.hibernate.orm.runtime.integration.HibernateOrmIntegrationStaticDescriptor; import io.quarkus.hibernate.orm.runtime.proxies.PreGeneratedProxies; import io.quarkus.hibernate.orm.runtime.tenant.DataSourceTenantConnectionResolver; @@ -424,7 +425,8 @@ public void build(RecorderContext recorderContext, HibernateOrmRecorder recorder List integrationBuildItems, ProxyDefinitionsBuildItem proxyDefinitions, BuildProducer feature, - BuildProducer beanContainerListener) throws Exception { + BuildProducer beanContainerListener, + LaunchModeBuildItem launchMode) throws Exception { feature.produce(new FeatureBuildItem(Feature.HIBERNATE_ORM)); validateHibernatePropertiesNotUsed(); @@ -455,6 +457,9 @@ public void build(RecorderContext recorderContext, HibernateOrmRecorder recorder for (String integratorClassName : ServiceUtil.classNamesNamedIn(classLoader, INTEGRATOR_SERVICE_FILE)) { integratorClasses.add((Class) recorderContext.classProxy(integratorClassName)); } + if (launchMode.getLaunchMode() == LaunchMode.DEVELOPMENT) { + integratorClasses.add(HibernateOrmDevConsoleIntegrator.class); + } Map> integrationStaticDescriptors = HibernateOrmIntegrationStaticConfiguredBuildItem .collectDescriptors(integrationBuildItems); diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/devconsole/DevConsoleProcessor.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/devconsole/DevConsoleProcessor.java index 6d07160dbbb98d..93187d742ec581 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/devconsole/DevConsoleProcessor.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/devconsole/DevConsoleProcessor.java @@ -3,13 +3,13 @@ import io.quarkus.deployment.IsDevelopment; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.devconsole.spi.DevConsoleRuntimeTemplateInfoBuildItem; -import io.quarkus.hibernate.orm.runtime.devconsole.PersistenceUnitInfoSupplier; +import io.quarkus.hibernate.orm.runtime.devconsole.HibernateOrmDevConsoleInfoSupplier; public class DevConsoleProcessor { @BuildStep(onlyIf = IsDevelopment.class) public DevConsoleRuntimeTemplateInfoBuildItem collectDeploymentUnits() { - return new DevConsoleRuntimeTemplateInfoBuildItem("persistence", new PersistenceUnitInfoSupplier()); + return new DevConsoleRuntimeTemplateInfoBuildItem("persistence", new HibernateOrmDevConsoleInfoSupplier()); } } diff --git a/extensions/hibernate-orm/deployment/src/main/resources/dev-templates/persistence-units.html b/extensions/hibernate-orm/deployment/src/main/resources/dev-templates/persistence-units.html index 9d01ed27546604..2f3de66167e5f4 100644 --- a/extensions/hibernate-orm/deployment/src/main/resources/dev-templates/persistence-units.html +++ b/extensions/hibernate-orm/deployment/src/main/resources/dev-templates/persistence-units.html @@ -23,14 +23,14 @@ {#for unit in info:persistence.persistenceUnits} {count}. - {unit.name} + {unit}

Create script: Copy

-
{info:persistence.createDDLs.get(unit.getName())}
+
{info:persistence.createDDLs.get(unit)}
{/for} diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/FastBootHibernatePersistenceProvider.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/FastBootHibernatePersistenceProvider.java index de7625fd8e5f15..12562f20b16ecf 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/FastBootHibernatePersistenceProvider.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/FastBootHibernatePersistenceProvider.java @@ -1,6 +1,5 @@ package io.quarkus.hibernate.orm.runtime; -import java.io.StringWriter; import java.util.Collections; import java.util.List; import java.util.Map; @@ -100,28 +99,6 @@ public boolean generateSchema(String persistenceUnitName, Map map) { return true; } - /** - * TODO: Figure out how to provide separate "create" and "drop" scripts. Currently this only do "create". - * - * A variant of {@link #generateSchema(String persistenceUnitName, Map map)} that returns the SQL script as a string. - * - * @param persistenceUnitName PU name - * @param map should be always null, as Quarkus doesn't allow to provide any properties in runtime. - * @return schema as string - */ - @SuppressWarnings("rawtypes") - public String generateSchemaToString(String persistenceUnitName, Map map) { - final FastBootEntityManagerFactoryBuilder builder = (FastBootEntityManagerFactoryBuilder) getEntityManagerFactoryBuilderOrNull( - persistenceUnitName, map); - if (builder == null) { - log.trace("Could not obtain matching EntityManagerFactoryBuilder, returning null"); - return null; - } - StringWriter createWriter = new StringWriter(); - builder.generateSchema(createWriter); - return createWriter.toString(); - } - @Override public ProviderUtil getProviderUtil() { return providerUtil; diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/PersistenceUnitsHolder.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/PersistenceUnitsHolder.java index b675f8eb597560..fb9ba1c76f1569 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/PersistenceUnitsHolder.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/PersistenceUnitsHolder.java @@ -14,7 +14,6 @@ import io.quarkus.hibernate.orm.runtime.boot.QuarkusPersistenceUnitDefinition; import io.quarkus.hibernate.orm.runtime.proxies.PreGeneratedProxies; import io.quarkus.hibernate.orm.runtime.recording.RecordedState; -import io.quarkus.runtime.LaunchMode; public final class PersistenceUnitsHolder { @@ -55,13 +54,7 @@ public static RecordedState popRecordedState(String persistenceUnitName) { if (persistenceUnitName == null) { key = NO_NAME_TOKEN; } - // Do not remove the PU metadata in dev-mode, we need them to generate information for DevUI pages. - // In normal mode, we want to remove these metadata as the associated memory cost is large. - if (LaunchMode.DEVELOPMENT == LaunchMode.current()) { - return persistenceUnits.recordedStates.get(key); - } else { - return persistenceUnits.recordedStates.remove(key); - } + return persistenceUnits.recordedStates.remove(key); } private static List convertPersistenceUnits( diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/FastBootEntityManagerFactoryBuilder.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/FastBootEntityManagerFactoryBuilder.java index a7316428f52811..f7709c9edf8ab2 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/FastBootEntityManagerFactoryBuilder.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/FastBootEntityManagerFactoryBuilder.java @@ -1,9 +1,7 @@ package io.quarkus.hibernate.orm.runtime.boot; import java.io.Serializable; -import java.io.Writer; import java.security.NoSuchAlgorithmException; -import java.util.EnumSet; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityNotFoundException; @@ -26,14 +24,9 @@ import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.spi.ServiceRegistryImplementor; -import org.hibernate.tool.hbm2ddl.SchemaExport; -import org.hibernate.tool.schema.TargetType; -import org.hibernate.tool.schema.internal.exec.ScriptTargetOutputToWriter; import org.hibernate.tool.schema.spi.CommandAcceptanceException; import org.hibernate.tool.schema.spi.DelayedDropRegistryNotAvailableImpl; import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator; -import org.hibernate.tool.schema.spi.ScriptTargetOutput; -import org.hibernate.tool.schema.spi.TargetDescriptor; import io.quarkus.hibernate.orm.runtime.RuntimeSettings; import io.quarkus.hibernate.orm.runtime.recording.PrevalidatedQuarkusMetadata; @@ -99,43 +92,6 @@ public void generateSchema() { cancel(); } - /** - * TODO: provide a second writer parameter for "drop" script, or create a second method. - * - * @param createWriter - */ - public void generateSchema(final Writer createWriter) { - try { - SchemaExport schemaExport = new SchemaExport(); - schemaExport.setFormat(true); - schemaExport.setDelimiter(";"); - schemaExport.doExecution(SchemaExport.Action.CREATE, false, metadata, standardServiceRegistry, - new TargetDescriptor() { - - @Override - public EnumSet getTargetTypes() { - return EnumSet.of(TargetType.SCRIPT); - } - - @Override - public ScriptTargetOutput getScriptTargetOutput() { - return new ScriptTargetOutputToWriter(createWriter) { - @Override - public void accept(String command) { - super.accept(command); - } - }; - } - }); - - } catch (Exception e) { - throw persistenceException("Error performing schema management", e); - } - - // release this builder - cancel(); - } - protected PersistenceException persistenceException(String message, Exception cause) { // Provide a comprehensible message if there is an issue with SSL support Throwable t = cause; diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/registry/PreconfiguredServiceRegistryBuilder.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/registry/PreconfiguredServiceRegistryBuilder.java index 065a0a9b2c777e..c90ac314b263ab 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/registry/PreconfiguredServiceRegistryBuilder.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/registry/PreconfiguredServiceRegistryBuilder.java @@ -106,13 +106,7 @@ public StandardServiceRegistryImpl buildNewServiceRegistry() { final Map settingsCopy = new HashMap(); settingsCopy.putAll(configurationValues); - // FIXME: resetAndReactivate() throws "IllegalStateException: Can't reactivate an active registry!" - // during persistenceProvider.generateSchema() execution (a new PersistenceProvider instance is constructed - // during this call). - // Is it OK to skip the resetAndReactivate() call when the registry is already active? - if (!destroyedRegistry.isActive()) { - destroyedRegistry.resetAndReactivate(bootstrapServiceRegistry, initiators, providedServices, settingsCopy); - } + destroyedRegistry.resetAndReactivate(bootstrapServiceRegistry, initiators, providedServices, settingsCopy); return destroyedRegistry; // return new StandardServiceRegistryImpl( diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/PersistenceUnitInfoSupplier.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/HibernateOrmDevConsoleInfoSupplier.java similarity index 54% rename from extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/PersistenceUnitInfoSupplier.java rename to extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/HibernateOrmDevConsoleInfoSupplier.java index a6810be366e355..787184a154d822 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/PersistenceUnitInfoSupplier.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/HibernateOrmDevConsoleInfoSupplier.java @@ -1,70 +1,89 @@ package io.quarkus.hibernate.orm.runtime.devconsole; +import java.io.StringWriter; import java.util.ArrayList; +import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Supplier; -import javax.persistence.spi.PersistenceProviderResolverHolder; - -import io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider; -import io.quarkus.hibernate.orm.runtime.PersistenceUnitsHolder; import org.hibernate.LockOptions; +import org.hibernate.boot.Metadata; import org.hibernate.engine.spi.NamedQueryDefinition; import org.hibernate.engine.spi.NamedSQLQueryDefinition; -import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; import org.hibernate.mapping.PersistentClass; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.hibernate.tool.schema.TargetType; +import org.hibernate.tool.schema.internal.exec.ScriptTargetOutputToWriter; +import org.hibernate.tool.schema.spi.ScriptTargetOutput; +import org.hibernate.tool.schema.spi.TargetDescriptor; -import io.quarkus.hibernate.orm.runtime.recording.RecordedState; +public class HibernateOrmDevConsoleInfoSupplier implements Supplier { -public class PersistenceUnitInfoSupplier implements Supplier { + private static final PersistenceUnitsInfo INSTANCE = new PersistenceUnitsInfo(); @Override public PersistenceUnitsInfo get() { - return composePersistenceUnitsInfo(PersistenceUnitsHolder.getPersistenceUnitDescriptors()); + return INSTANCE; } - private PersistenceUnitsInfo composePersistenceUnitsInfo(List persistenceUnits) { - PersistenceUnitsInfo persistenceUnitsInfo = new PersistenceUnitsInfo(); - - FastBootHibernatePersistenceProvider persistenceProvider = (FastBootHibernatePersistenceProvider) PersistenceProviderResolverHolder - .getPersistenceProviderResolver().getPersistenceProviders().get(0); - - for (PersistenceUnitDescriptor descriptor : persistenceUnits) { - persistenceUnitsInfo.getPersistenceUnits().add(descriptor); - RecordedState recordedState = PersistenceUnitsHolder.popRecordedState(descriptor.getName()); + public static void pushPersistenceUnit(String persistenceUnitName, + Metadata metadata, ServiceRegistry serviceRegistry) { + INSTANCE.getPersistenceUnits().add(persistenceUnitName); - String schema = persistenceProvider.generateSchemaToString(descriptor.getName(), null); - persistenceUnitsInfo.createDDLs.put(descriptor.getName(), schema); + String schema = generateDDL(SchemaExport.Action.CREATE, metadata, serviceRegistry); + INSTANCE.createDDLs.put(persistenceUnitName, schema); - for (String className : descriptor.getManagedClassNames()) { - PersistentClass entityBinding = recordedState.getMetadata().getEntityBinding(className); - persistenceUnitsInfo.managedEntities.add(new PersistenceUnitInfoSupplier.EntityInfo(className, - entityBinding.getTable().getName(), descriptor.getName())); - } + for (PersistentClass entityBinding : metadata.getEntityBindings()) { + INSTANCE.managedEntities.add(new HibernateOrmDevConsoleInfoSupplier.EntityInfo(entityBinding.getClassName(), + entityBinding.getTable().getName(), persistenceUnitName)); + } - for (NamedQueryDefinition queryDefinition : recordedState.getMetadata().getNamedQueryDefinitions()) { - persistenceUnitsInfo.namedQueries.add(new QueryInfo(queryDefinition)); - } + for (NamedQueryDefinition queryDefinition : metadata.getNamedQueryDefinitions()) { + INSTANCE.namedQueries.add(new QueryInfo(queryDefinition)); + } - for (NamedSQLQueryDefinition staticQueryDefinition : recordedState.getMetadata().getNamedNativeQueryDefinitions()) { - persistenceUnitsInfo.namedNativeQueries.add(new QueryInfo(staticQueryDefinition)); - } + for (NamedSQLQueryDefinition staticQueryDefinition : metadata.getNamedNativeQueryDefinitions()) { + INSTANCE.namedNativeQueries.add(new QueryInfo(staticQueryDefinition)); } + } - return persistenceUnitsInfo; + private static String generateDDL(SchemaExport.Action action, Metadata metadata, ServiceRegistry serviceRegistry) { + SchemaExport schemaExport = new SchemaExport(); + schemaExport.setFormat(true); + schemaExport.setDelimiter(";"); + StringWriter writer = new StringWriter(); + schemaExport.doExecution(action, false, metadata, serviceRegistry, + new TargetDescriptor() { + @Override + public EnumSet getTargetTypes() { + return EnumSet.of(TargetType.SCRIPT); + } + + @Override + public ScriptTargetOutput getScriptTargetOutput() { + return new ScriptTargetOutputToWriter(writer) { + @Override + public void accept(String command) { + super.accept(command); + } + }; + } + }); + return writer.toString(); } public static class PersistenceUnitsInfo { - private final List persistenceUnits = new ArrayList<>(); + private final List persistenceUnits = new ArrayList<>(); private final List managedEntities = new ArrayList<>(); private final List namedQueries = new ArrayList<>(); private final List namedNativeQueries = new ArrayList<>(); private final Map createDDLs = new HashMap<>(); - public List getPersistenceUnits() { + public List getPersistenceUnits() { return persistenceUnits; } diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/HibernateOrmDevConsoleIntegrator.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/HibernateOrmDevConsoleIntegrator.java new file mode 100644 index 00000000000000..eeda5d69895342 --- /dev/null +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/HibernateOrmDevConsoleIntegrator.java @@ -0,0 +1,23 @@ +package io.quarkus.hibernate.orm.runtime.devconsole; + +import org.hibernate.boot.Metadata; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.integrator.spi.Integrator; +import org.hibernate.jpa.AvailableSettings; +import org.hibernate.service.spi.SessionFactoryServiceRegistry; + +public class HibernateOrmDevConsoleIntegrator implements Integrator { + @Override + public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactoryImplementor, + SessionFactoryServiceRegistry sessionFactoryServiceRegistry) { + HibernateOrmDevConsoleInfoSupplier.pushPersistenceUnit( + (String) sessionFactoryImplementor.getProperties().get(AvailableSettings.PERSISTENCE_UNIT_NAME), + metadata, sessionFactoryServiceRegistry); + } + + @Override + public void disintegrate(SessionFactoryImplementor sessionFactoryImplementor, + SessionFactoryServiceRegistry sessionFactoryServiceRegistry) { + // Nothing to do + } +}