
org.nuiton.topia.service.sql.internal.SqlRequestSetConsumerContext Maven / Gradle / Ivy
The newest version!
package org.nuiton.topia.service.sql.internal;
/*-
* #%L
* ToPIA Extension :: API
* %%
* Copyright (C) 2018 - 2022 Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* .
* #L%
*/
import com.google.common.collect.Multimap;
import com.zaxxer.hikari.pool.HikariProxyConnection;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType;
import org.nuiton.topia.persistence.HibernateAvailableSettings;
import org.nuiton.topia.persistence.TopiaEntity;
import org.nuiton.topia.persistence.TopiaException;
import org.nuiton.topia.persistence.TopiaPersistenceContext;
import org.nuiton.topia.persistence.internal.AbstractTopiaApplicationContext;
import org.nuiton.topia.persistence.internal.AbstractTopiaPersistenceContext;
import io.ultreia.java4all.util.sql.SqlScriptWriter;
import io.ultreia.java4all.util.sql.BlobsContainer;
import org.nuiton.topia.service.sql.blob.TopiaEntitySqlBlob;
import org.nuiton.topia.service.sql.blob.TopiaEntitySqlBlobModel;
import org.nuiton.topia.service.sql.model.TopiaEntitySqlSelectArgument;
import org.postgresql.PGConnection;
import org.postgresql.jdbc.PgConnection;
import org.postgresql.largeobject.LargeObject;
import org.postgresql.largeobject.LargeObjectManager;
import javax.sql.rowset.serial.SerialBlob;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Date;
import java.util.EnumSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
/**
* Created on 25/09/2020.
*
* @author Tony Chemit - [email protected]
* @since 1.28
*/
public class SqlRequestSetConsumerContext implements Closeable {
private static final Logger log = LogManager.getLogger(SqlRequestSetConsumerContext.class);
private final SqlRequestSet request;
private final AbstractTopiaApplicationContext> sourceTopiaApplicationContext;
private final Set blobsContainerBuilders;
private final TopiaEntitySqlBlobModel blobModel;
private TopiaPersistenceContext sourcePersistenceContext;
private SqlScriptWriter writer;
private Date date;
public static String ids(TopiaEntitySqlSelectArgument selectArgument) {
if (selectArgument == null) {
return null;
}
String ids;
Set filterIds = selectArgument.getIds();
if (filterIds.size() == 1) {
ids = " = '" + filterIds.iterator().next() + "'";
} else {
StringBuilder in = new StringBuilder();
filterIds.stream().map(id -> String.format(", '%s'", id)).forEach(in::append);
ids = String.format(" IN ( %s )", in.substring(2));
}
return ids;
}
public SqlRequestSetConsumerContext(AbstractTopiaApplicationContext> sourceTopiaApplicationContext, SqlRequestSet request) {
this.request = request;
this.sourceTopiaApplicationContext = sourceTopiaApplicationContext;
this.blobModel = request.getBlobModel();
this.blobsContainerBuilders = new LinkedHashSet<>();
}
public String getNewParentId() {
return request.getNewParentId();
}
public SqlRequestSet getRequest() {
return request;
}
public AbstractTopiaApplicationContext> getSourceTopiaApplicationContext() {
return sourceTopiaApplicationContext;
}
public String ids(TopiaEntitySqlSelectArgument selectArgument, boolean optimize) {
if (optimize) {
selectArgument = checkArgument(selectArgument);
}
return ids(selectArgument);
}
public TopiaEntitySqlSelectArgument checkArgument(TopiaEntitySqlSelectArgument selectArgument) {
if (selectArgument != null) {
// find out if we are deleting all data
Set ids = selectArgument.getIds();
String firstId = ids.iterator().next();
Class entityClass = getSourceTopiaApplicationContext().getConfiguration().getTopiaIdFactory().getClassName(firstId);
long count = getSourcePersistenceContext().getDao(entityClass).count();
if (count == ids.size()) {
// for all data : no select argument required
selectArgument = null;
}
}
return selectArgument;
}
public void addSchemaExportScript(Class extends Dialect> dialectType, SchemaExport.Action action) throws IOException {
Path sqlScriptFile = Files.createTempFile(request.getPath().getParent(), "schemaExport_" + action.name() + "_", ".sql");
try {
Metadata hibernateMetadata = getSourcePersistenceContext().getHibernateSupport().getHibernateMetadata();
StandardServiceRegistry serviceRegistry = ((MetadataImplementor) hibernateMetadata).getMetadataBuildingOptions().getServiceRegistry();
Properties properties = new Properties();
properties.putAll(serviceRegistry.getService(ConfigurationService.class).getSettings());
properties.put(HibernateAvailableSettings.DIALECT, dialectType.getName());
BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder().build();
StandardServiceRegistryBuilder ssrBuilder = new StandardServiceRegistryBuilder(bsr);
ssrBuilder.applySettings(properties);
StandardServiceRegistry registry = ssrBuilder.build();
try {
new SchemaExport()
.setOutputFile(sqlScriptFile.toFile().getAbsolutePath())
.setDelimiter(";")
.execute(EnumSet.of(TargetType.SCRIPT), action, hibernateMetadata, registry);
} finally {
StandardServiceRegistryBuilder.destroy(registry);
}
getWriter().writeScript(sqlScriptFile);
} finally {
if (Files.exists(sqlScriptFile)) {
Files.delete(sqlScriptFile);
}
}
}
public AbstractTopiaPersistenceContext getSourcePersistenceContext() {
if (sourcePersistenceContext == null) {
sourcePersistenceContext = sourceTopiaApplicationContext.newPersistenceContext();
}
return (AbstractTopiaPersistenceContext) sourcePersistenceContext;
}
@Override
public void close() throws IOException {
try {
if (sourcePersistenceContext != null) {
sourcePersistenceContext.close();
}
} finally {
if (writer != null) {
writer.close();
}
}
}
public SqlScriptWriter getWriter() {
if (writer == null) {
SqlScriptWriter.Builder writerBuilder = SqlScriptWriter.builder(request.getPath());
if (request.isGzip()) {
writerBuilder.gzip();
}
writer = writerBuilder.build();
}
return writer;
}
public Optional> getBlobsContainersBuilder() {
if (blobsContainerBuilders.isEmpty()) {
return Optional.empty();
}
return Optional.of(blobsContainerBuilders);
}
public void registerBlobsContainer(BlobsContainer.Builder builder) {
blobsContainerBuilders.add(builder);
}
public int getReadFetchSize() {
return request.getReadFetchSize();
}
public void flushBlobs(Map blobsContainersBuilder) {
Optional> optionalBlobsContainers = getBlobsContainersBuilder();
if (optionalBlobsContainers.isPresent()) {
Set blobsContainers = optionalBlobsContainers.get();
for (BlobsContainer.Builder blobsContainerBuilder : blobsContainers) {
String tableName = blobsContainerBuilder.getTableName();
BlobsContainer blobsContainer = blobsContainerBuilder.build();
BlobsContainer existingBlobsContainer = blobsContainersBuilder.get(tableName);
if (existingBlobsContainer != null) {
existingBlobsContainer.add(blobsContainer.getBlobsById());
} else {
blobsContainersBuilder.put(tableName, blobsContainer);
}
}
}
}
public Map initBlobsBuilder(boolean useBlob, String schemaAndTableName) {
Map result = new TreeMap<>();
if (useBlob) {
TopiaEntitySqlBlob blobModel = this.blobModel.getEntries().values().stream().filter(m -> schemaAndTableName.equals(m.schemaAndTableName())).findFirst().orElseThrow();
List blobColumns = blobModel.getColumnNames();
for (String blobColumn : blobColumns) {
BlobsContainer.Builder blobBuilder = BlobsContainer.builder(schemaAndTableName, blobColumn);
registerBlobsContainer(blobBuilder);
result.put(blobColumn, blobBuilder);
}
}
return result;
}
public void copyBlob(PreparedStatement preparedStatement, String topiaId, Object columnValue,
BlobsContainer.Builder blobsBuilder) throws SQLException {
if (columnValue == null) {
return;
}
Connection connection = preparedStatement.getConnection();
InputStream stream;
int size;
if (columnValue instanceof Long) {
PGConnection pgConnection;
if (connection instanceof PgConnection) {
pgConnection = (PGConnection) connection;
} else if (connection instanceof HikariProxyConnection) {
HikariProxyConnection connection1 = (HikariProxyConnection) connection;
try {
Field field = connection1.getClass().getSuperclass().getDeclaredField("delegate");
field.setAccessible(true);
pgConnection = (PGConnection) field.get(connection1);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
throw new IllegalStateException("Can't know how to manage connection: " + connection);
}
LargeObjectManager largeObjectAPI = pgConnection.getLargeObjectAPI();
LargeObject obj = largeObjectAPI.open((long) columnValue, LargeObjectManager.READ);
size = obj.size();
stream = obj.getInputStream();
} else {
Blob blob = (Blob) columnValue;
stream = blob.getBinaryStream();
SerialBlob serialBlob = new SerialBlob(blob);
size = (int) serialBlob.length();
}
try (ByteArrayOutputStream stringWriter = new ByteArrayOutputStream(size)) {
stringWriter.write(stream);
blobsBuilder.addBlob(topiaId, stringWriter.toByteArray());
log.debug("Add blob: " + topiaId);
} catch (IOException e) {
throw new TopiaException("Can't add blob", e);
}
}
public List generateOrder(Multimap parents, String sentinel) {
List result = new LinkedList<>();
generateOrder(parents, parents.get(sentinel), result);
return result;
}
public Date now() {
if (date == null) {
date = new Date();
}
return date;
}
private void generateOrder(Multimap parents, Collection toDo, List result) {
for (String id : toDo) {
if (!result.contains(id)) {
log.debug(String.format("Add id: %s (pos %d)", id, result.size()));
result.add(id);
}
Collection topiaIds = parents.get(id);
generateOrder(parents, topiaIds, result);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy