Skip to content

Commit

Permalink
Push Hibernate ORM DevConsole info on startup instead of pulling it a…
Browse files Browse the repository at this point in the history
…t runtime
  • Loading branch information
yrodiere committed Aug 2, 2021
1 parent 3052098 commit 7e87bb0
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -424,7 +425,8 @@ public void build(RecorderContext recorderContext, HibernateOrmRecorder recorder
List<HibernateOrmIntegrationStaticConfiguredBuildItem> integrationBuildItems,
ProxyDefinitionsBuildItem proxyDefinitions,
BuildProducer<FeatureBuildItem> feature,
BuildProducer<BeanContainerListenerBuildItem> beanContainerListener) throws Exception {
BuildProducer<BeanContainerListenerBuildItem> beanContainerListener,
LaunchModeBuildItem launchMode) throws Exception {

feature.produce(new FeatureBuildItem(Feature.HIBERNATE_ORM));
validateHibernatePropertiesNotUsed();
Expand Down Expand Up @@ -455,6 +457,9 @@ public void build(RecorderContext recorderContext, HibernateOrmRecorder recorder
for (String integratorClassName : ServiceUtil.classNamesNamedIn(classLoader, INTEGRATOR_SERVICE_FILE)) {
integratorClasses.add((Class<? extends Integrator>) recorderContext.classProxy(integratorClassName));
}
if (launchMode.getLaunchMode() == LaunchMode.DEVELOPMENT) {
integratorClasses.add(HibernateOrmDevConsoleIntegrator.class);
}

Map<String, List<HibernateOrmIntegrationStaticDescriptor>> integrationStaticDescriptors = HibernateOrmIntegrationStaticConfiguredBuildItem
.collectDescriptors(integrationBuildItems);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@
{#for unit in info:persistence.persistenceUnits}
<tr>
<td>{count}.</td>
<td>{unit.name}</td>
<td>{unit}</td>
<td>
<p>
<b>Create script:</b>
<a href="#" onclick="copyToClipboard('create-script-{count}');">
<i class="fa fa-clipboard"></i><span class="badge">Copy</span></a>
</p>
<pre id="create-script-{count}" class="ddl-script">{info:persistence.createDDLs.get(unit.getName())}</pre>
<pre id="create-script-{count}" class="ddl-script">{info:persistence.createDDLs.get(unit)}</pre>
</td>
</tr>
{/for}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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<PersistenceUnitDescriptor> convertPersistenceUnits(
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<TargetType> 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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<HibernateOrmDevConsoleInfoSupplier.PersistenceUnitsInfo> {

public class PersistenceUnitInfoSupplier implements Supplier<PersistenceUnitInfoSupplier.PersistenceUnitsInfo> {
private static final PersistenceUnitsInfo INSTANCE = new PersistenceUnitsInfo();

@Override
public PersistenceUnitsInfo get() {
return composePersistenceUnitsInfo(PersistenceUnitsHolder.getPersistenceUnitDescriptors());
return INSTANCE;
}

private PersistenceUnitsInfo composePersistenceUnitsInfo(List<PersistenceUnitDescriptor> 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<TargetType> 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<PersistenceUnitDescriptor> persistenceUnits = new ArrayList<>();
private final List<String> persistenceUnits = new ArrayList<>();
private final List<EntityInfo> managedEntities = new ArrayList<>();
private final List<QueryInfo> namedQueries = new ArrayList<>();
private final List<QueryInfo> namedNativeQueries = new ArrayList<>();
private final Map<String, String> createDDLs = new HashMap<>();

public List<PersistenceUnitDescriptor> getPersistenceUnits() {
public List<String> getPersistenceUnits() {
return persistenceUnits;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
}

0 comments on commit 7e87bb0

Please sign in to comment.