/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.modelgenerator.xml.wizards.jdbc;
import java.sql.DatabaseMetaData;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.teiid.designer.jdbc.JdbcException;
import org.teiid.designer.jdbc.metadata.JdbcCatalog;
import org.teiid.designer.jdbc.metadata.JdbcDatabase;
import org.teiid.designer.jdbc.metadata.JdbcNode;
import org.teiid.designer.jdbc.metadata.JdbcTable;
import org.teiid.designer.jdbc.relational.impl.Context;
import org.teiid.designer.jdbc.relational.impl.RelationalModelProcessorImpl;
import org.teiid.designer.metamodels.core.ModelAnnotation;
import org.teiid.designer.metamodels.core.ModelType;
import org.teiid.designer.metamodels.relational.AccessPattern;
import org.teiid.designer.metamodels.relational.Catalog;
import org.teiid.designer.metamodels.relational.Column;
import org.teiid.designer.metamodels.relational.RelationalEntity;
import org.teiid.designer.metamodels.relational.RelationalFactory;
import org.teiid.designer.metamodels.relational.Table;
import org.teiid.designer.metamodels.relational.util.RelationalTypeMapping;
import org.teiid.designer.modelgenerator.xml.model.DatabaseMetaDataImpl;
import org.teiid.designer.modelgenerator.xml.modelextension.BaseXMLRelationalExtensionManager;
import org.teiid.designer.modelgenerator.xml.modelextension.XMLHTTPExtensionManager;
import org.teiid.designer.modelgenerator.xml.modelextension.impl.XMLRequestResponseExtensionManagerImpl;
import org.teiid.designer.modelgenerator.xml.wizards.StateManager;
import org.teiid.designer.modelgenerator.xml.wizards.XsdAsRelationalImportWizard;
import org.teiid.designer.schema.tools.model.schema.QName;
import org.teiid.designer.schema.tools.processing.SchemaUtil;
/**
* @since 8.0
*/
public class XmlSchemaAsRelationalModelProcessor extends RelationalModelProcessorImpl {
BaseXMLRelationalExtensionManager extensions;
public XmlSchemaAsRelationalModelProcessor() {
super();
extensions = XsdAsRelationalImportWizard.extManager;
}
public XmlSchemaAsRelationalModelProcessor( RelationalFactory factory ) {
super(factory);
extensions = XsdAsRelationalImportWizard.extManager;
}
public XmlSchemaAsRelationalModelProcessor( RelationalFactory factory,
RelationalTypeMapping mapping ) {
super(factory, mapping);
extensions = XsdAsRelationalImportWizard.extManager;
}
@Override
protected void setNameAndNameInSource( final RelationalEntity entity,
final String name,
final JdbcNode node,
final Context context,
List problems ) {
// This is the only callout that we get from the base model processor,
// so we use it for things other than name and name in source
super.setNameAndNameInSource(entity, name, node, context, problems);
processNewEntity(entity, name, node, context);
}
protected void processNewEntity( final RelationalEntity entity,
final String name,
final JdbcNode node,
final Context context ) {
if (entity instanceof Catalog) {
Catalog catalog = (Catalog)entity;
processNewCatalog(name, node, context, catalog);
} else if (entity instanceof Table) {
Table table = (Table)entity;
processNewTable(name, node, context, table);
}
}
protected void processNewTable( final String name,
final JdbcNode node,
final Context context,
Table table ) {
JdbcTable tableNode = (JdbcTable)node;
// Let's make sure that the model type is physical, and that the
// resource and
// the entity are appropriately related to each other, so that we can
// set the extension attributes.
// This looks awfully hacky to me.
ModelAnnotation modelAnnotation = context.getModelContents().getModelAnnotation();
ModelType oldtype = modelAnnotation.getModelType();
Catalog oldCatalog = table.getCatalog();
modelAnnotation.setModelType(ModelType.PHYSICAL_LITERAL);
context.getResource().getContents().add(table);
try {
setTableNamespacePrefixes(table, tableNode, name, context);
addResponseField(table, tableNode, name, context);
processRequestAttributes(table, tableNode, name, context);
} finally {
context.getResource().getContents().remove(table);
if (oldCatalog != null) {
table.setCatalog(oldCatalog);
}
modelAnnotation.setModelType(oldtype);
}
}
protected void processNewCatalog( final String name,
final JdbcNode node,
final Context context,
Catalog catalog ) {
setCatalogNamespacePrefixes(catalog, node, name, context);
}
@Override
protected String computeNameInSource( final RelationalEntity object,
final String name,
final JdbcNode node,
final Context context,
final boolean forced,
List problems ) {
String retval;
if (object instanceof org.teiid.designer.metamodels.relational.Table) {
retval = getTableNameInSource(object, name, node, context);
} else if (object instanceof org.teiid.designer.metamodels.relational.Column) {
retval = getColumnNameInSource(object, name, node, context);
} else if (object instanceof org.teiid.designer.metamodels.relational.PrimaryKey) {
retval = getPrimaryKeyNameInSource(object, name, node, context);
} else if (object instanceof org.teiid.designer.metamodels.relational.ForeignKey) {
retval = getForeignKeyNameInSource(object, name, node, context);
} else {
retval = super.computeNameInSource(object, name, node, context, forced, problems);
}
return retval;
}
protected String getTableNameInSource( final RelationalEntity object,
final String name,
final JdbcNode node,
final Context context ) {
DatabaseMetaDataImpl databaseMetaData = getMetaDataImpl(context);
QName qname = getTableQName(node);
String nameInSource = databaseMetaData.getTableNameInSource(name, qname.getNamespace());
return nameInSource;
}
protected String getColumnNameInSource( final RelationalEntity object,
final String name,
final JdbcNode node,
final Context context ) {
DatabaseMetaDataImpl databaseMetaData = getMetaDataImpl(context);
QName qname = getTableQName(node);
String nameInSource = databaseMetaData.getColumnNameInSource(name, qname.getNamespace(), qname.getLName());
return nameInSource;
}
protected String getPrimaryKeyNameInSource( final RelationalEntity object,
final String name,
final JdbcNode node,
final Context context ) {
DatabaseMetaDataImpl databaseMetaData = getMetaDataImpl(context);
QName qname = getTableQName(node);
String nameInSource = databaseMetaData.getPrimaryKeyNameInSource(name, qname.getNamespace());
return nameInSource;
}
protected String getForeignKeyNameInSource( final RelationalEntity object,
final String name,
final JdbcNode node,
final Context context ) {
DatabaseMetaDataImpl databaseMetaData = getMetaDataImpl(context);
QName qname = getTableQName(node);
String nameInSource = databaseMetaData.getForeignKeyNameInSource(name, qname.getNamespace());
return nameInSource;
}
private QName getTableQName( final JdbcNode node ) {
JdbcTable jdbcTable = (JdbcTable)node;
String tableName = jdbcTable.getName();
String tableNamespace = null;
JdbcNode catalogNode = node;
while (catalogNode != null && !(catalogNode instanceof JdbcCatalog)) {
catalogNode = catalogNode.getParent();
}
if (catalogNode instanceof JdbcCatalog) {
JdbcCatalog jdbcCatalog = (JdbcCatalog)catalogNode;
tableNamespace = jdbcCatalog.getName();
}
QName qname = SchemaUtil.getQName(tableNamespace, tableName);
return qname;
}
private void setCatalogNamespacePrefixes( Catalog entity,
JdbcNode node,
String name,
Context context ) {
// Let's make sure that the model type is physical, and that the
// resource and
// the entity are appropriately related to each other, so that we can
// set the extension attributes.
// This looks awfully hacky to me.
ModelAnnotation modelAnnotation = context.getModelContents().getModelAnnotation();
ModelType oldtype = modelAnnotation.getModelType();
modelAnnotation.setModelType(ModelType.PHYSICAL_LITERAL);
context.getResource().getContents().add(entity);
try {
setNamespacePrefixesAttribute(entity, name, context);
} finally {
context.getResource().getContents().remove(entity);
modelAnnotation.setModelType(oldtype);
}
}
private void addResponseField( Table entity,
JdbcTable node,
String name,
Context context ) {
QName qname = getTableQName(node);
DatabaseMetaDataImpl metaDataImpl = getMetaDataImpl(context);
Boolean requestTriState = metaDataImpl.isRequestOrResponseTable(qname);
if (requestTriState == null) {
return;
}
boolean request = requestTriState.booleanValue();
List problems = new ArrayList();
Column column = getFactory().createColumn();
column.setOwner(entity);
String colName = request ? XsdAsRelationalImportWizard.RESPONSE_ID_OUT_COL_NAME : XsdAsRelationalImportWizard.RESPONSE_ID_IN_COL_NAME;
int arbitrarySize = 1000; // arbitrary number
setColumnInfo(column,
node,
context,
problems,
colName,
Types.VARCHAR,
String.class.getName(),
arbitrarySize,
0,
0,
DatabaseMetaData.columnNullable,
"", //$NON-NLS-1$
0);
column.setSelectable(request);
if (extensions instanceof XMLHTTPExtensionManager) {
((XMLHTTPExtensionManager)extensions).setColumnRoleAttribute(column,
(request ? XMLRequestResponseExtensionManagerImpl.RESPONSE_OUT_ROLE : XMLRequestResponseExtensionManagerImpl.RESPONSE_IN_ROLE));
((XMLHTTPExtensionManager)extensions).setColumnInputParamAttribute(column, (request ? Boolean.FALSE : Boolean.TRUE));
}
if (!request) {
AccessPattern accessPattern = getFactory().createAccessPattern();
accessPattern.setName(colName);
accessPattern.setTable(entity);
accessPattern.getColumns().add(column);
}
// TODO: figure out a way to get the problem back to the caller
}
private void processRequestAttributes( Table entity,
JdbcTable node,
String name,
Context context ) {
QName qname = getTableQName(node);
DatabaseMetaDataImpl metaDataImpl = getMetaDataImpl(context);
Boolean requestTriState = metaDataImpl.isRequestOrResponseTable(qname);
if (requestTriState == null) {
return;
}
boolean request = requestTriState.booleanValue();
if (request) {
setXpathRootForInputAttribute(entity);
}
}
private void setXpathRootForInputAttribute( final RelationalEntity entity ) {
String xrfi_attribute_value = null;
xrfi_attribute_value = "/"; // else set it to / since a blank value is invalid. //$NON-NLS-1$
((XMLHTTPExtensionManager)extensions).setXPathRootForInputAttribute(entity, xrfi_attribute_value);
}
private void setTableNamespacePrefixes( Table entity,
JdbcTable node,
String name,
Context context ) {
QName qname = getTableQName(node);
// TODO: remove this hack
if (qname.getNamespace() != null && qname.getNamespace().equals(StateManager.globalNamespace)) {
qname.setNamespace(null);
}
setNamespacePrefixesAttribute(entity, qname.getNamespace(), context);
}
private static String quoteString( String str ) {
if (str.indexOf('\'') == -1) {
return '\'' + str + '\'';
} else if (str.indexOf('\"') == -1) {
return '\"' + str + '\"';
} else {
// The namespace contains both ' and ".
StringBuffer retval = new StringBuffer();
retval.append('\'');
for (int i = 0; i < str.length(); ++i) {
char c = str.charAt(i);
if (c == '\'') {
retval.append("'"); //$NON-NLS-1$
} else {
retval.append(c);
}
}
retval.append('\'');
return retval.toString();
}
}
private void setNamespacePrefixesAttribute( final RelationalEntity entity,
final String name,
final Context context ) {
DatabaseMetaDataImpl metaDataImpl = getMetaDataImpl(context);
if (metaDataImpl != null) {
Map prefixes = metaDataImpl.getNamespacePrefixes(name);
StringBuffer namespacePrefixes = new StringBuffer();
for (Iterator iter = prefixes.keySet().iterator(); iter.hasNext();) {
Object oNamespace = iter.next();
if (oNamespace == null) continue;
String namespace = (String)oNamespace;
Object oPrefix = prefixes.get(oNamespace);
String prefix = (String)oPrefix;
if (namespacePrefixes.length() != 0) {
namespacePrefixes.append(' ');
}
namespacePrefixes.append("xmlns"); //$NON-NLS-1$
if (!(prefix == null || prefix.equals(""))) { //$NON-NLS-1$
namespacePrefixes.append(':');
}
if (prefix != null) namespacePrefixes.append(prefix);
namespacePrefixes.append('=');
String quotedNamespace = quoteString(namespace);
namespacePrefixes.append(quotedNamespace);
}
extensions.setNamespacePrefixesAttribute(entity, namespacePrefixes.toString());
}
}
private DatabaseMetaDataImpl getMetaDataImpl( final Context context ) {
JdbcDatabase db = context.getJdbcDatabase();
DatabaseMetaData metaData;
DatabaseMetaDataImpl metaDataImpl;
try {
metaData = db.getDatabaseMetaData();
} catch (JdbcException e) {
context.getWarnings().add(e);
metaData = null;
}
if (metaData instanceof DatabaseMetaDataImpl) {
metaDataImpl = (DatabaseMetaDataImpl)metaData;
} else {
metaDataImpl = null;
}
return metaDataImpl;
}
}