/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com
*
*******************************************************************************
*
* 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.pentaho.di.starmodeler.generator;
import java.util.List;
import java.util.Set;
import org.pentaho.di.core.util.Utils;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.starmodeler.ConceptUtil;
import org.pentaho.di.starmodeler.DefaultIDs;
import org.pentaho.metadata.model.Domain;
import org.pentaho.metadata.model.LogicalModel;
import org.pentaho.metadata.model.LogicalTable;
import org.pentaho.metadata.model.SqlDataSource;
import org.pentaho.metadata.model.SqlDataSource.DataSourceType;
import org.pentaho.metadata.model.SqlPhysicalModel;
import org.pentaho.metadata.model.SqlPhysicalTable;
import org.pentaho.metadata.model.concept.Concept;
import org.pentaho.metadata.model.concept.types.LocalizedString;
public class MetadataGenerator {
private Domain logicalDomain;
private List<DatabaseMeta> databases;
/**
* @param logicalDomain The logical domain containing star schemas without physical layer.
* @param databases The list of databases to reference
*/
public MetadataGenerator(Domain logicalDomain, List<DatabaseMeta> databases) {
this.logicalDomain = logicalDomain;
this.databases = databases;
}
public Domain generatePhysicalMetadataModel() throws KettleException {
// First do some checking and lookups...
//
String targetDatabaseName = ConceptUtil.getString(logicalDomain, DefaultIDs.DOMAIN_TARGET_DATABASE);
if (Utils.isEmpty(targetDatabaseName)) {
throw new KettleException("Please specify a target database!");
}
DatabaseMeta targetDatabaseMeta = DatabaseMeta.findDatabase(databases, targetDatabaseName);
if (targetDatabaseMeta==null) {
throw new KettleException("Target database with name '"+targetDatabaseName+"' can't be found!");
}
// Now start creation of a new domain with physical underpinning.
//
Domain domain = new Domain();
// Copy the domain information...
//
domain.setId( createId("DOMAIN", null, domain) );
domain.setName(logicalDomain.getName());
domain.setDescription(logicalDomain.getDescription());
// Now copy all the models...
//
for (LogicalModel logicalModel : logicalDomain.getLogicalModels()) {
// Copy model information...
//
LogicalModel model = new LogicalModel();
model.setId( createId("MODEL", domain, model));
model.setName(logicalModel.getName());
model.setDescription(logicalModel.getDescription());
// Create a physical model...
//
SqlPhysicalModel sqlModel = new SqlPhysicalModel();
sqlModel.setDatasource(createSqlDataSource(targetDatabaseMeta));
model.setPhysicalModel(sqlModel);
for (LogicalTable logicalTable : logicalModel.getLogicalTables()) {
LogicalTable table = new LogicalTable();
table.setId( createId("LOGICAL_TABLE", logicalModel, logicalTable) );
table.setName(logicalTable.getName());
table.setDescription(logicalTable.getDescription());
String targetTable = ConceptUtil.getString(logicalTable, DefaultIDs.LOGICAL_TABLE_PHYSICAL_TABLE_NAME);
SqlPhysicalTable sqlTable = new SqlPhysicalTable(sqlModel);
table.setPhysicalTable(sqlTable);
// Copy name & description from physical level...
//
sqlTable.setId( createId("PHYSICAL_TABLE", logicalModel, logicalTable));
sqlTable.setName(logicalTable.getName());
sqlTable.setDescription(logicalTable.getDescription());
sqlTable.setTableType(ConceptUtil.getTableType(logicalTable));
sqlTable.setTargetSchema(targetDatabaseMeta.getPreferredSchemaName());
sqlTable.setTargetTable(targetTable);
}
}
return domain;
}
private SqlDataSource createSqlDataSource(DatabaseMeta databaseMeta) {
SqlDataSource dataSource = new SqlDataSource();
dataSource.setDatabaseName(databaseMeta.getDatabaseName());
dataSource.setHostname(databaseMeta.getHostname());
dataSource.setUsername(databaseMeta.getUsername());
dataSource.setPassword(databaseMeta.getPassword());
dataSource.setPort(databaseMeta.getDatabasePortNumberString());
dataSource.setAttributes(databaseMeta.getExtraOptions());
DataSourceType dataSourceType;
switch(databaseMeta.getAccessType()) {
case DatabaseMeta.TYPE_ACCESS_NATIVE : dataSourceType = DataSourceType.NATIVE; break;
case DatabaseMeta.TYPE_ACCESS_ODBC : dataSourceType = DataSourceType.ODBC; break;
case DatabaseMeta.TYPE_ACCESS_JNDI : dataSourceType = DataSourceType.JNDI; break;
case DatabaseMeta.TYPE_ACCESS_OCI : dataSourceType = DataSourceType.OCI; break;
default: dataSourceType = DataSourceType.CUSTOM; break;
}
dataSource.setType(dataSourceType);
return dataSource;
}
private String createId(String prefix, Concept parent, Concept item) {
StringBuilder id = new StringBuilder(prefix);
if (parent!=null) {
id.append("_");
id.append( extractId(parent));
}
id.append("_");
id.append( extractId(item));
return id.toString();
}
private String extractId(Concept item) {
LocalizedString localizedName = item.getName();
Set<String> locales = localizedName.getLocales();
if (locales.isEmpty()) return "";
// Just grab the first locale we come across
// This should normally only one for the star modeler
//
String locale = locales.iterator().next();
String id = localizedName.getLocalizedString(locale);
id = id.toUpperCase().replace(" ", "_");
return id;
}
/**
* @return the logicalDomain
*/
public Domain getLogicalDomain() {
return logicalDomain;
}
/**
* @param logicalDomain the logicalDomain to set
*/
public void setLogicalDomain(Domain logicalDomain) {
this.logicalDomain = logicalDomain;
}
/**
* @return the databases
*/
public List<DatabaseMeta> getDatabases() {
return databases;
}
/**
* @param databases the databases to set
*/
public void setDatabases(List<DatabaseMeta> databases) {
this.databases = databases;
}
}