Java tutorial
/* * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.teiid.spring.autoconfigure; import java.io.File; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.hibernate.MappingException; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.internal.InFlightMetadataCollectorImpl; import org.hibernate.boot.internal.MetadataBuilderImpl.MetadataBuildingOptionsImpl; import org.hibernate.boot.internal.MetadataBuildingContextRootImpl; import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.JDBCBinder; import org.hibernate.cfg.reveng.DatabaseCollector; import org.hibernate.cfg.reveng.DefaultReverseEngineeringStrategy; import org.hibernate.cfg.reveng.MappingsDatabaseCollector; import org.hibernate.cfg.reveng.ReverseEngineeringRuntimeInfo; import org.hibernate.cfg.reveng.ReverseEngineeringStrategy; import org.hibernate.cfg.reveng.TableIdentifier; import org.hibernate.cfg.reveng.dialect.JDBCMetaDataDialect; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.spi.Mapping; import org.hibernate.id.factory.IdentifierGeneratorFactory; import org.hibernate.mapping.Index; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PrimaryKey; import org.hibernate.mapping.Property; import org.hibernate.mapping.UniqueKey; import org.hibernate.service.ServiceRegistry; import org.hibernate.tool.hbm2x.ArtifactCollector; import org.hibernate.tool.hbm2x.HibernateMappingExporter; import org.hibernate.type.BasicTypeRegistry; import org.hibernate.type.Type; import org.hibernate.type.TypeFactory; import org.hibernate.type.TypeResolver; import org.springframework.context.ApplicationContext; import org.teiid.core.types.JDBCSQLTypeInfo; import org.teiid.dialect.TeiidDialect; import org.teiid.metadata.BaseColumn.NullType; import org.teiid.metadata.Column; import org.teiid.metadata.ForeignKey; import org.teiid.metadata.KeyRecord; import org.teiid.metadata.MetadataFactory; import org.teiid.metadata.Table; import org.teiid.spring.views.EntityBaseView; public class SchemaBuilderUtility { private static final File TMP_DIR = new File(System.getProperty("java.io.tmpdir") + "/teiid"); public void generateVBLSchema(ApplicationContext context, MetadataFactory source, MetadataFactory target, Dialect dialect, MetadataSources metadataSources) { generateVBLSchema(source, target); StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder( (BootstrapServiceRegistry) metadataSources.getServiceRegistry()) .applySetting(AvailableSettings.DIALECT, dialect).build(); ArtifactCollector files = generateHibernateModel(source, serviceRegistry); for (File f : files.getFiles("hbm.xml")) { metadataSources.addFile(f); } } public void generateVBLSchema(MetadataFactory source, MetadataFactory target) { for (Table srcTable : source.getSchema().getTables().values()) { Table table = target.addTable(srcTable.getName()); for (Column srcColumn : srcTable.getColumns()) { Column c = target.addColumn(srcColumn.getName(), srcColumn.getRuntimeType(), table); c.setUpdatable(true); if (srcColumn.isAutoIncremented()) { c.setAutoIncremented(true); } c.setLength(srcColumn.getLength()); c.setScale(srcColumn.getScale()); c.setPrecision(srcColumn.getPrecision()); c.setNullType(srcColumn.getNullType()); c.setDefaultValue(srcColumn.getDefaultValue()); } table.setVirtual(true); table.setSupportsUpdate(true); if (srcTable.getPrimaryKey() != null) { target.addPrimaryKey(srcTable.getPrimaryKey().getName(), RedirectionSchemaBuilder.getColumnNames(srcTable.getPrimaryKey().getColumns()), table); } if (!srcTable.getForeignKeys().isEmpty()) { for (ForeignKey fk : srcTable.getForeignKeys()) { target.addForeignKey(fk.getName(), RedirectionSchemaBuilder.getColumnNames(fk.getColumns()), fk.getReferenceColumns(), fk.getReferenceTableName(), table); } } if (!srcTable.getUniqueKeys().isEmpty()) { for (KeyRecord kr : srcTable.getUniqueKeys()) { target.addIndex(kr.getName(), false, RedirectionSchemaBuilder.getColumnNames(kr.getColumns()), table); } } if (!srcTable.getIndexes().isEmpty()) { for (KeyRecord kr : srcTable.getIndexes()) { target.addIndex(kr.getName(), true, RedirectionSchemaBuilder.getColumnNames(kr.getColumns()), table); } } table.setSelectTransformation(EntityBaseView.buildSelectPlan(table, source.getSchema().getName())); } } // this is not used currently public static Metadata generateHbmModel(ConnectionProvider provider, Dialect dialect) throws SQLException { MetadataSources metadataSources = new MetadataSources(); ServiceRegistry registry = metadataSources.getServiceRegistry(); StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder( (BootstrapServiceRegistry) registry).applySetting(AvailableSettings.DIALECT, TeiidDialect.class) .addService(ConnectionProvider.class, provider).addService(JdbcEnvironment.class, new JdbcEnvironmentImpl(provider.getConnection().getMetaData(), dialect)) .build(); ReverseEngineeringStrategy strategy = new DefaultReverseEngineeringStrategy(); MetadataBuildingOptions options = new MetadataBuildingOptionsImpl(serviceRegistry); BasicTypeRegistry basicTypeRegistry = new BasicTypeRegistry(); TypeResolver typeResolver = new TypeResolver(basicTypeRegistry, new TypeFactory()); InFlightMetadataCollectorImpl metadataCollector = new InFlightMetadataCollectorImpl(options, typeResolver); MetadataBuildingContext buildingContext = new MetadataBuildingContextRootImpl(options, null, metadataCollector); JDBCBinder binder = new JDBCBinder(serviceRegistry, new Properties(), buildingContext, strategy, false); Metadata metadata = metadataCollector.buildMetadataInstance(buildingContext); binder.readFromDatabase(null, null, buildMapping(metadata)); HibernateMappingExporter exporter = new HibernateMappingExporter() { @Override protected Metadata getMetadata() { return metadata; } }; exporter.start(); return metadata; } private static Mapping buildMapping(final Metadata metadata) { return new Mapping() { /** * Returns the identifier type of a mapped class */ @Override public Type getIdentifierType(String persistentClass) throws MappingException { final PersistentClass pc = metadata.getEntityBinding(persistentClass); if (pc == null) { throw new MappingException("persistent class not known: " + persistentClass); } return pc.getIdentifier().getType(); } @Override public String getIdentifierPropertyName(String persistentClass) throws MappingException { final PersistentClass pc = metadata.getEntityBinding(persistentClass); if (pc == null) { throw new MappingException("persistent class not known: " + persistentClass); } if (!pc.hasIdentifierProperty()) { return null; } return pc.getIdentifierProperty().getName(); } @Override public Type getReferencedPropertyType(String persistentClass, String propertyName) throws MappingException { final PersistentClass pc = metadata.getEntityBinding(persistentClass); if (pc == null) { throw new MappingException("persistent class not known: " + persistentClass); } Property prop = pc.getProperty(propertyName); if (prop == null) { throw new MappingException("property not known: " + persistentClass + '.' + propertyName); } return prop.getType(); } @Override public IdentifierGeneratorFactory getIdentifierGeneratorFactory() { return null; } }; } static class TeiidJDBCBinder extends JDBCBinder { private InFlightMetadataCollectorImpl metadataCollector; private MetadataFactory source; private ReverseEngineeringStrategy strategy; TeiidJDBCBinder(ServiceRegistry serviceRegistry, Properties properties, MetadataBuildingContext mdbc, ReverseEngineeringStrategy revengStrategy, boolean preferBasicCompositeIds, InFlightMetadataCollectorImpl metadataCollector, MetadataFactory source) { super(serviceRegistry, properties, mdbc, revengStrategy, preferBasicCompositeIds); this.metadataCollector = metadataCollector; this.source = source; this.strategy = revengStrategy; } @Override public DatabaseCollector readDatabaseSchema(String catalog, String schema) throws SQLException { DatabaseCollector dbs = new MappingsDatabaseCollector(metadataCollector, new JDBCMetaDataDialect()); Map<String, org.hibernate.mapping.Table> foundTables = new java.util.HashMap<>(); for (Table table : source.getSchema().getTables().values()) { org.hibernate.mapping.Table ht = metadataCollector.addTable(null, null, table.getName(), null, false); dbs.addTable(null, null, table.getName()); // Add columns for (Column column : table.getColumns()) { org.hibernate.mapping.Column hc = new org.hibernate.mapping.Column(); hc.setName(column.getName()); hc.setSqlTypeCode(new Integer(JDBCSQLTypeInfo.getSQLType(column.getRuntimeType()))); hc.setLength(column.getLength()); hc.setPrecision(column.getPrecision()); hc.setScale(column.getScale()); hc.setNullable(column.getNullType() == NullType.Nullable); ht.addColumn(hc); } // Add primary key KeyRecord pk = table.getPrimaryKey(); if (pk != null) { PrimaryKey hpk = new PrimaryKey(ht); hpk.setName(pk.getName()); for (Column column : pk.getColumns()) { hpk.addColumn(ht.getColumn(new org.hibernate.mapping.Column(column.getName()))); } ht.setPrimaryKey(hpk); } // add unique keys, indexes etc. if (!table.getUniqueKeys().isEmpty()) { for (KeyRecord key : table.getUniqueKeys()) { UniqueKey uk = new UniqueKey(); uk.setName(key.getName()); uk.setTable(ht); ht.addUniqueKey(uk); for (Column column : key.getColumns()) { uk.addColumn(ht.getColumn(new org.hibernate.mapping.Column(column.getName()))); } } } if (!table.getIndexes().isEmpty()) { for (KeyRecord key : table.getIndexes()) { Index idx = new Index(); idx.setName(key.getName()); idx.setTable(ht); ht.addIndex(idx); for (Column column : key.getColumns()) { idx.addColumn(ht.getColumn(new org.hibernate.mapping.Column(column.getName()))); } } } foundTables.put(table.getName(), ht); } // Add foreign keys Map<String, List<org.hibernate.mapping.ForeignKey>> oneToManyCandidates = new HashMap<String, List<org.hibernate.mapping.ForeignKey>>(); for (Table table : source.getSchema().getTables().values()) { org.hibernate.mapping.Table ht = foundTables.get(table.getName()); for (ForeignKey fk : table.getForeignKeys()) { org.hibernate.mapping.Table refht = foundTables.get(fk.getReferenceTableName()); List<org.hibernate.mapping.Column> columns = new ArrayList<>(); List<org.hibernate.mapping.Column> refColumns = new ArrayList<>(); for (Column column : fk.getColumns()) { columns.add(ht.getColumn(new org.hibernate.mapping.Column(column.getName()))); } for (String column : fk.getReferenceColumns()) { refColumns.add(refht.getColumn(new org.hibernate.mapping.Column(column))); } String className = strategy.tableToClassName(TableIdentifier.create(ht)); org.hibernate.mapping.ForeignKey key = ht.createForeignKey(fk.getName(), columns, className, null, refColumns); key.setReferencedTable(refht); List<org.hibernate.mapping.ForeignKey> existing = oneToManyCandidates.get(className); if (existing == null) { existing = new ArrayList<org.hibernate.mapping.ForeignKey>(); oneToManyCandidates.put(className, existing); } existing.add(key); } } dbs.setOneToManyCandidates(oneToManyCandidates); strategy.configure(ReverseEngineeringRuntimeInfo.createInstance(null, null, dbs)); return dbs; } } public static ArtifactCollector generateHibernateModel(MetadataFactory source, StandardServiceRegistry serviceRegistry) { ReverseEngineeringStrategy strategy = new DefaultReverseEngineeringStrategy(); MetadataBuildingOptions options = new MetadataBuildingOptionsImpl(serviceRegistry); BasicTypeRegistry basicTypeRegistry = new BasicTypeRegistry(); TypeResolver typeResolver = new TypeResolver(basicTypeRegistry, new TypeFactory()); InFlightMetadataCollectorImpl metadataCollector = new InFlightMetadataCollectorImpl(options, typeResolver); MetadataBuildingContext buildingContext = new MetadataBuildingContextRootImpl(options, null, metadataCollector); TeiidJDBCBinder binder = new TeiidJDBCBinder(serviceRegistry, new Properties(), buildingContext, strategy, false, metadataCollector, source); Metadata metadata = metadataCollector.buildMetadataInstance(buildingContext); binder.readFromDatabase(null, null, buildMapping(metadata)); HibernateMappingExporter exporter = new HibernateMappingExporter() { @Override protected Metadata getMetadata() { return metadata; } }; exporter.setOutputDirectory(TMP_DIR); exporter.start(); return exporter.getArtifactCollector(); } }