/*
* 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.wsdl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.xsd.XSDSchema;
import org.jdom.Namespace;
import org.teiid.designer.modelgenerator.wsdl.model.Message;
import org.teiid.designer.modelgenerator.wsdl.model.Model;
import org.teiid.designer.modelgenerator.wsdl.model.Operation;
import org.teiid.designer.modelgenerator.wsdl.model.Part;
import org.teiid.designer.modelgenerator.wsdl.schema.extensions.SOAPSchemaProcessor;
import org.teiid.designer.modelgenerator.wsdl.util.NameUtil;
import org.teiid.designer.modelgenerator.xml.modelextension.impl.XMLRequestResponseExtensionManagerImpl;
import org.teiid.designer.schema.tools.model.jdbc.Column;
import org.teiid.designer.schema.tools.model.jdbc.DataType;
import org.teiid.designer.schema.tools.model.jdbc.Table;
import org.teiid.designer.schema.tools.model.jdbc.internal.ColumnImpl;
import org.teiid.designer.schema.tools.model.jdbc.internal.DataTypeImpl;
import org.teiid.designer.schema.tools.model.jdbc.internal.TableImpl;
import org.teiid.designer.schema.tools.model.schema.Relationship;
import org.teiid.designer.schema.tools.model.schema.RootElement;
import org.teiid.designer.schema.tools.model.schema.SchemaModel;
import org.teiid.designer.schema.tools.processing.RelationshipProcessor;
import org.teiid.designer.schema.tools.processing.RelationshipProcessorFactory;
import org.teiid.designer.schema.tools.processing.SchemaProcessingException;
import org.teiid.designer.schema.tools.processing.SchemaProcessor;
/**
* @since 8.0
*/
public class TableBuilder {
public static final String RESPONSE_IN = "ResponseIn"; //$NON-NLS-1$
public static final String RESPONSE_OUT = "ResponseOut"; //$NON-NLS-1$
public static final String XML_SCHEMA_URI = "http://www.w3.org/2001/XMLSchema"; //$NON-NLS-1$
public static final String MMID = "mmid"; //$NON-NLS-1$
XSDSchema[] m_schemas;
SchemaModel m_schemaModel;
private Model m_model;
public Map getNamespaces() {
return m_model.getNamespaces();
}
public Collection createTables( Operation[] opers ) throws ModelBuildingException {
// This method has the potential of being VERY slow since we do a LOT
// of looping over collections (operations, messages, parts, elements,
// tables, columns).
// If performance becomes an issue when building the model we may
// need to revisit this or even worse
// add a progress monitor into the mix.
HashMap tables = new HashMap(opers.length * 2);
// walk up to get the schemas and namespaces
m_model = opers[0].getBinding().getPort().getService().getModel();
m_schemas = m_model.getSchemas();
try {
// process the schemas and get the schema model
SchemaProcessor processor = new SOAPSchemaProcessor(null);
processor.representTypes(true);
processor.setNamespaces(this.m_model.getNamespaces());
processor.processSchemas(m_schemas);
m_schemaModel = processor.getSchemaModel();
// create the relationship processor that builds the tables
final int maxOccursMax = 4;
final int maxParents = Integer.MAX_VALUE;
final int maxFields = Integer.MAX_VALUE;
// get the list of messages from the operations
ArrayList messages = getMessages(opers);
for (Iterator messageIter = messages.iterator(); messageIter.hasNext();) {
Message message = (Message)messageIter.next();
// create the base table for the message
Table baseTable = createBaseTable(message);
String soapAction = null;
if (message.isRequest()) {
soapAction = message.getOperation().getSOAPAction();
}
SoapBindingInfo info = null;
if (message.getOperation() != null) {
info = message.getOperation().getSoapBindingInfo();
}
SOAPTable baseTableWrapper = new SOAPTableImpl(baseTable, message.isRequest(), soapAction, info);
// add it to the return list
String tableName = baseTable.getCatalog() + "." + baseTable.getName(); //$NON-NLS-1$
tables.put(tableName, baseTableWrapper);
// loop over the message parts
Part[] parts = message.getParts();
for (int i = 0; i < parts.length; i++) {
Part part = parts[i];
String elementNamespace;
String elementName;
if (part.isElement()) {
elementName = part.getElementName();
elementNamespace = part.getElementNamespace();
} else {
elementName = part.getTypeName(); // get the name here also
elementNamespace = part.getTypeNamespace();
}
if (elementNamespace.equalsIgnoreCase(XML_SCHEMA_URI)) {
Column add = createColumn(part);
baseTable.addColumn(add);
} else {
// since the relationship processor changes the model we need to
// clone the schema model each time
SchemaModel clone = m_schemaModel.copy();
String topName = null;
if (part.isElement()) {
// now find the element you want
RootElement theElement = null;
List roots = m_schemaModel.getPotentialRootElements();
for (Iterator rootIter = roots.iterator(); rootIter.hasNext();) {
RootElement root = (RootElement)rootIter.next();
if ((root == null && elementNamespace.trim().length() == 0)
|| (root != null && root.getNamespace().equalsIgnoreCase(elementNamespace))) {
if (root!=null && root.getName().equalsIgnoreCase(elementName)) {
theElement = root;
break;
}
}
}
// prepare to use the RelationshipProcessor
// create a hash containing my element
HashSet eSet = new HashSet(1);
eSet.add(theElement);
// now set that element as the only root element
clone.setSelectedRootElements(eSet);
topName = theElement.getName();
} else {
clone.setTypeAsRoot(elementName, elementNamespace);
topName = elementName;
}
// create the tables
RelationshipProcessor relProc;
if (message.isRequest()) {
relProc = RelationshipProcessorFactory.getRequestProcessor();
} else {
relProc = RelationshipProcessorFactory.getQueryOptimizingProcessor(maxOccursMax,
maxParents,
maxFields);
}
relProc.calculateRelationshipTypes(clone);
// get them back as a list
List tabList = clone.getTables();
// get the root table
SOAPTable top = new SOAPTableImpl(getRootTable(tabList, topName));
top.setCatalog(baseTable.getCatalog());
top.setSchema(baseTable.getSchema());
top.setName(NameUtil.normalizeNameForRelationalTable(top.getName()));
Column[] columns = top.getColumns();
for (int col = 0; col < columns.length; col++) {
Column column = columns[col];
column.setName(NameUtil.normalizeNameForRelationalTable(column.getName()));
}
// If the top table is an instance of a SOAP Array, it needs special handling.
// I think the test below should only be true for SOAP Arrays but I could be wrong.
if (!message.isRequest() && (top.getMaxOccurs() == -1 || top.getMaxOccurs() > 1)) {
// use as a child to the response and create a keyed relation.
createKeyInChild(top, baseTable.getName());
addMMIdColumn(baseTable, ""); //$NON-NLS-1$
top.setName(part.getName());
StringBuffer combinedXPath = new StringBuffer(baseTable.getOutputXPath());
if (!baseTable.getOutputXPath().endsWith("/")) { //$NON-NLS-1$
combinedXPath.append("/"); //$NON-NLS-1$
}
combinedXPath.append(part.getName());
combinedXPath.append("/*"); //$NON-NLS-1$
String newXPathPrefix = combinedXPath.toString();
top.setOutputXPath(newXPathPrefix);
Table[] table = {top};
processChildren(table, message.isRequest(), tables, baseTable, newXPathPrefix);
} else {
// fold top into baseTable
if (!part.isElement()) {
String inputXPath = top.getInputXPath();
if (inputXPath.indexOf('/') != 0) {
inputXPath = "/" + inputXPath; //$NON-NLS-1$
}
top.setInputXPath("/" + part.getName() + inputXPath); //$NON-NLS-1$
}
mergeTables(baseTable, top, message.isRequest());
processChildren(top.getChildTables(), message.isRequest(), tables, baseTable, null);
}
}
}
}
} catch (SchemaProcessingException se) {
throw new ModelBuildingException(se);
}
return tables.values();
}
private void createKeyInChild( Table table,
String parentName ) {
String childColumnName = parentName + "_" + MMID; //$NON-NLS-1$
Column keyColumn = new ColumnImpl();
keyColumn.setName(childColumnName);
keyColumn.setDataType(new DataTypeImpl("string", XML_SCHEMA_URI)); //$NON-NLS-1$
keyColumn.setRole(XMLRequestResponseExtensionManagerImpl.DATA_ROLE);
keyColumn.setOutputXPath("../../@com.metamatrix.xml.xpathpart"); //$NON-NLS-1$
keyColumn.setIsForeignKey(true);
table.addColumn(keyColumn);
}
private void processChildren( Table[] tabs,
boolean isRequest,
HashMap tables,
Table baseTable,
String xPathPrefix ) {
for (int i = 0; i < tabs.length; i++) {
Table table = tabs[i];
String tableName = baseTable.getCatalog() + "." + baseTable.getSchema() + "." + table.getName(); //$NON-NLS-1$ //$NON-NLS-2$
tableName = NameUtil.normalizeNameForRelationalTable(tableName);
// did we already process this table?
if (tables.get(tableName) != null) continue;
table.setCatalog(baseTable.getCatalog());
table.setSchema(baseTable.getSchema());
table.setName(NameUtil.normalizeNameForRelationalTable(table.getName()));
checkForForeignKeys(baseTable, table, tables);
mergeNamespacePrefixes(table, baseTable);
Column[] columns = table.getColumns();
for (int col = 0; col < columns.length; col++) {
Column column = columns[col];
column.setName(NameUtil.normalizeNameForRelationalTable(column.getName()));
if (isRequest) {
if (!column.getName().equals(MMID)) {
setInputColumnValues(column.getOutputXPath(), column);
}
}
}
if (!isRequest) {
addResponseInColumn(table);
}
tables.put(tableName, new SOAPTableImpl(table, isRequest, null, null));
processChildren(table, tables, isRequest, baseTable, xPathPrefix);
}
}
private void processChildren( Table table,
HashMap tables,
boolean isRequest,
Table baseTable,
String xPathPrefix ) {
Table[] tabs = table.getChildTables();
for (int i = 0; i < tabs.length; i++) {
String tableName = table.getCatalog() + "." + table.getSchema() + "." + tabs[i].getName(); //$NON-NLS-1$ //$NON-NLS-2$
tableName = NameUtil.normalizeNameForRelationalTable(tableName);
checkForForeignKeys(table, tabs[i], tables);
// did we already process the table?
if (tables.get(tableName) != null) continue;
if (null != xPathPrefix) {
String currentXPath = tabs[i].getOutputXPath();
if (currentXPath.charAt(0) != '/') {
tabs[i].setOutputXPath(xPathPrefix + "/" + currentXPath); //$NON-NLS-1$
} else {
tabs[i].setOutputXPath(xPathPrefix + currentXPath);
}
}
tabs[i].setName(NameUtil.normalizeNameForRelationalTable(tabs[i].getName()));
tabs[i].setCatalog(table.getCatalog());
tabs[i].setSchema(table.getSchema());
mergeNamespacePrefixes(table, baseTable);
tables.put(tableName, new SOAPTableImpl(tabs[i], isRequest, null, null));
Column[] columns = tabs[i].getColumns();
for (int col = 0; col < columns.length; col++) {
Column column = columns[col];
column.setName(NameUtil.normalizeNameForRelationalTable(column.getName()));
}
if (!isRequest) {
addResponseInColumn(tabs[i]);
}
processChildren(tabs[i], tables, isRequest, table, xPathPrefix);
}
}
private Table getRootTable( List tabList,
String name ) {
Table tab = null;
for (Iterator iter = tabList.iterator(); iter.hasNext();) {
Table temp = (Table)iter.next();
String tempName = temp.getName();
if (tempName.indexOf('(') != -1) {
tempName = tempName.substring(0, tempName.indexOf('('));
}
if (tempName.equalsIgnoreCase(name)) {
tab = temp;
break;
}
}
return tab;
}
private void mergeTables( Table baseTable,
Table toMerge,
boolean isRequest ) {
mergeNamespacePrefixes(baseTable, toMerge);
// columns
String inputXpathPrepend = toMerge.getInputXPath();
String outputXpathPrepend = toMerge.getOutputXPath();
Column[] cols = toMerge.getColumns();
// is the only column mmid?
if (isRequest && cols.length == 1) {
// must be an empty element - create a column that allows for empty
Column empty = new ColumnImpl();
empty.setName(NameUtil.normalizeNameForRelationalTable(toMerge.getName()));
empty.setIsInputParameter(true);
empty.setIsRequiredValue(false);
empty.setInputXPath(toMerge.getOutputXPath());
empty.setDataType(new DataTypeImpl("string", XML_SCHEMA_URI)); //$NON-NLS-1$
baseTable.addColumn(empty);
}
for (int i = 0; i < cols.length; i++) {
Column source = cols[i];
if (!source.getName().equals(MMID)) {
Column candidate = copyColumn(inputXpathPrepend, outputXpathPrepend, source, isRequest);
baseTable.addColumn(candidate);
} else if (!isRequest) {
this.addMMIdColumn(baseTable, outputXpathPrepend);
}
}
// This object is added so that in later processing we can generate the
// XPath to the parent's key. Without it we have lost the connection: more hackery for defect 23639
baseTable.setElement(toMerge.getElement());
baseTable.setBase(true);
}
public static void mergeNamespacePrefixes( Table toTable,
Table fromTable ) {
Namespace[] ns = extractNamespaces(fromTable.getNamespaceDeclaration());
Namespace[] existing = extractNamespaces(toTable.getNamespaceDeclaration());
for (int i = 0; i < ns.length; i++) {
// ensure its not already there
// TODO: if the same prefix is declared for different uri's were boned.
String nsUri = ns[i].getURI();
String nsPrefix = ns[i].getPrefix();
boolean already = false;
for (int j = 0; j < existing.length; j++) {
if (existing[j].getURI().equals(nsUri) && existing[j].getPrefix().equals(nsPrefix)) {
already = true;
break;
}
}
if (!already) toTable.addNamespace(ns[i]);
}
}
private Column copyColumn( String inputXpathPrepend,
String outputXpathPrepend,
Column source,
boolean isRequest ) {
Column candidate = new ColumnImpl();
candidate.setName(NameUtil.normalizeNameForRelationalTable(source.getName()));
candidate.setDataType(source.getDataType());
candidate.setMultipleValues(source.getMultipleValues());
// extension properties
// these need to be factored out later
if (isRequest) {
// have to use output xpath since input xpath is not populated.
if (inputXpathPrepend.lastIndexOf('/') == inputXpathPrepend.length() - 1) {
setInputColumnValues(inputXpathPrepend + source.getOutputXPath(), candidate);
} else {
setInputColumnValues(inputXpathPrepend + "/" + source.getOutputXPath(), candidate); //$NON-NLS-1$
}
} else {
candidate.setOutputXPath(outputXpathPrepend + "/" + source.getOutputXPath()); //$NON-NLS-1$
}
candidate.setRole(source.getRole());
return candidate;
}
private void setInputColumnValues( String baseXpath,
Column candidate ) {
// TODO: currently only output xpaths are created so until that is fixed we have to
// derive the output values
if (baseXpath.startsWith("/")) baseXpath = baseXpath.substring(1); //$NON-NLS-1$
// one thing we can be sure of
candidate.setIsInputParameter(true);
// we have to figure these out from the output xpath
// look for @ symbol which indicates that the column is an attribute
if (baseXpath.indexOf('@') >= 0) {
// its an attribute
candidate.setIsAttributeOfParent(true);
int atIndex = baseXpath.indexOf('@');
String attrName = baseXpath.substring(atIndex + 1);
String parentXpath = "/"; //$NON-NLS-1$
if (atIndex > 0) {
// substring up to 2 spaces before the @ (removes /@)
parentXpath = baseXpath.substring(0, baseXpath.indexOf('@') - 1);
if (parentXpath.endsWith("/")) parentXpath = parentXpath.substring(0, parentXpath.length() - 1); //$NON-NLS-1$
}
candidate.setDataAttributeName(attrName);
candidate.setInputXPath(parentXpath);
} else {
final String data = "/data()"; //$NON-NLS-1$
final String text = "/text()"; //$NON-NLS-1$
if (baseXpath.endsWith(data)) baseXpath = baseXpath.substring(0, baseXpath.length() - data.length());
if (baseXpath.endsWith(text)) baseXpath = baseXpath.substring(0, baseXpath.length() - text.length());
candidate.setInputXPath(baseXpath);
}
// should always be true for web services
candidate.setIsRequiredValue(true);
}
private static Namespace[] extractNamespaces( String namespaceDeclaration ) {
String temp = namespaceDeclaration;
String[] decls = temp.split("xmlns:"); //$NON-NLS-1$
Namespace[] retVal = new Namespace[decls.length - 1];
for (int i = 1; i < decls.length; i++) {
if (decls[i].startsWith("=")) { //$NON-NLS-1$
// TODO: how to handle default namespaces?
String suffix = decls[i].substring(2, decls[i].length() - 1);
retVal[i - 1] = Namespace.getNamespace(null, suffix);
} else {
// strip out the : before splitting
String[] nsParts = decls[i].substring(1).split("="); //$NON-NLS-1$
String prefix = nsParts[0].trim();
String suffix = nsParts[1].trim().substring(1, nsParts[1].trim().length() - 1);
retVal[i - 1] = Namespace.getNamespace(prefix, suffix);
}
}
return retVal;
}
private ArrayList getMessages( Operation[] opers ) {
ArrayList messages = new ArrayList(opers.length);
for (int i = 0; i < opers.length; i++) {
messages.add(opers[i].getInputMessage());
messages.add(opers[i].getOutputMessage());
// TODO: add this back in when the connector supports fault tables
/*
Fault[] faults = opers[i].getFaults();
for (int j = 0; j < faults.length; j++) {
messages.add(faults[j].getMessage());
}
*/
}
return messages;
}
private Table createBaseTable( Message msg ) {
Table table = new SOAPTableImpl();
if (msg.isRequest() || msg.isResponse()) {
table.setName(NameUtil.normalizeNameForRelationalTable(msg.getName()));
table.setSchema(msg.getOperation().getName());
table.setCatalog(msg.getOperation().getBinding().getPort().getService().getName());
} else {
table.setName(NameUtil.normalizeNameForRelationalTable(msg.getFault().getName()));
table.setSchema(msg.getFault().getOperation().getName());
table.setCatalog(msg.getFault().getOperation().getBinding().getPort().getService().getName());
}
String style = (msg.getOperation() == null) ? msg.getFault().getOperation().getBinding().getStyle() : msg.getOperation().getBinding().getStyle();
if (style.equalsIgnoreCase("RPC")) { //$NON-NLS-1$
String ns = ""; //$NON-NLS-1$
if (msg.getNamespaceURI() != null && !msg.getNamespaceURI().trim().equals("")) { //$NON-NLS-1$
// search for the prefix
ns = findNamespacePrefix(msg.getNamespaceURI().trim()) + ":"; //$NON-NLS-1$
}
if (msg.isRequest()) {
table.setInputXPath("/" + ns + table.getSchema()); //$NON-NLS-1$
table.setOutputXPath("/"); //$NON-NLS-1$
} else {
table.setOutputXPath("/" + ns + table.getSchema() + "Response"); //$NON-NLS-1$ //$NON-NLS-2$
}
} else {
table.setInputXPath("/"); //$NON-NLS-1$
table.setOutputXPath("/"); //$NON-NLS-1$
}
for (Iterator iter = m_model.getNamespaces().keySet().iterator(); iter.hasNext();) {
String prefix = (String)iter.next();
String uri = (String)m_model.getNamespaces().get(prefix);
Namespace ns = Namespace.getNamespace(prefix, uri);
table.addNamespace(ns);
}
if (msg.isResponse() || msg.isFault()) {
addResponseInColumn(table);
} else {
addResponseOutColumn(table);
}
return table;
}
private void addMMIdColumn( Table table,
String prefix ) {
Column col = new ColumnImpl();
DataType type = new DataTypeImpl("string", XML_SCHEMA_URI); //$NON-NLS-1$
col.setDataType(type);
col.setName("mmid"); //$NON-NLS-1$
col.setOutputXPath(prefix + "/@com.metamatrix.xml.xpathpart"); //$NON-NLS-1$
col.setRole(XMLRequestResponseExtensionManagerImpl.DATA_ROLE);
table.addColumn(col);
}
private void addResponseOutColumn( Table table ) {
Column col = new ColumnImpl();
DataType type = new DataTypeImpl("string", XML_SCHEMA_URI); //$NON-NLS-1$
col.setDataType(type);
col.setName(RESPONSE_OUT);
col.setRole(XMLRequestResponseExtensionManagerImpl.RESPONSE_OUT_ROLE);
table.addColumn(col);
}
private void addResponseInColumn( Table table ) {
Column col = new ColumnImpl();
DataType type = new DataTypeImpl("string", XML_SCHEMA_URI); //$NON-NLS-1$
col.setDataType(type);
col.setName(RESPONSE_IN);
col.setRole(XMLRequestResponseExtensionManagerImpl.RESPONSE_IN_ROLE);
col.setIsInputParameter(true);
table.addColumn(col);
}
private Column createColumn( Part part ) {
String name = (part.getElementName() == null) ? part.getName() : part.getElementName();
Column col = new ColumnImpl();
col.setName(NameUtil.normalizeNameForRelationalTable(name));
if (part.getElementNamespace() != null) {
m_model.addNamespaceToMap(part.getElementNamespace());
}
if (part.getMessage().isRequest()) {
col.setIsInputParameter(true);
col.setInputXPath(name);
} else {
col.setOutputXPath(name + "/text()"); //$NON-NLS-1$
}
// The part defined by an element or a type?
if (part.getTypeName() != null) {
col.setDataType(new DataTypeImpl(part.getTypeName(), part.getTypeNamespace()));
} else {
col.setDataType(new DataTypeImpl(part.getElementName(), part.getElementNamespace()));
}
return col;
}
public String findNamespacePrefix( String namespaceURI ) {
String prefix = null;
for (Iterator iter = m_model.getNamespaces().keySet().iterator(); iter.hasNext();) {
String key = (String)iter.next();
if (m_model.getNamespaces().get(key).equals(namespaceURI)) {
prefix = key;
}
}
if (prefix == null) {
m_model.addNamespaceToMap(namespaceURI);
prefix = findNamespacePrefix(namespaceURI);
}
return prefix;
}
private void checkForForeignKeys( Table parent,
Table child,
HashMap tables ) {
switch (child.getRelationToParent()) {
case Relationship.KEY_IN_CHILD:
String childColumnName = parent.getName() + "_" + MMID; //$NON-NLS-1$
// TODO: how do we calculate the parent's mmid xpath?
Column keyColumn = new ColumnImpl();
keyColumn.setName(childColumnName);
keyColumn.setDataType(new DataTypeImpl("string", XML_SCHEMA_URI)); //$NON-NLS-1$
keyColumn.setRole(XMLRequestResponseExtensionManagerImpl.DATA_ROLE);
keyColumn.setOutputXPath(getChildKeyColumnXPath(parent, child));
keyColumn.setIsForeignKey(true);
child.addColumn(keyColumn);
break;
case Relationship.KEY_IN_PARENT_SINGLE:
// TODO: how do we calculate the child's mmid xpath?
String parentColumnName = child.getName() + "_" + MMID; //$NON-NLS-1$
String parentOutputXPath = ""; //$NON-NLS-1$
Column parentKeyColumn = new ColumnImpl();
parentKeyColumn.setName(parentColumnName);
parentKeyColumn.setDataType(new DataTypeImpl("string", XML_SCHEMA_URI)); //$NON-NLS-1$
parentKeyColumn.setRole(XMLRequestResponseExtensionManagerImpl.DATA_ROLE);
parentKeyColumn.setOutputXPath(parentOutputXPath);
parentKeyColumn.setIsForeignKey(true);
parent.addColumn(parentKeyColumn);
break;
case Relationship.RELATIONSHIP_TABLE:
if (tables.containsKey(parent.getName() + "_" + child.getName())) { //$NON-NLS-1$
break; // don't create more than one relationship table between the same tables.
}
Table relTable = new SOAPTableImpl();
relTable.setCatalog(parent.getCatalog());
relTable.setSchema(parent.getSchema());
relTable.setName(parent.getName() + "_" + child.getName()); //$NON-NLS-1$
relTable.setOutputXPath("/"); //$NON-NLS-1$
String relParentColumnName = parent.getName() + "_" + MMID; //$NON-NLS-1$
String relParentOutputXPath = parent.getOutputXPath() + "/@com.metamatrix.xml.xpathpart"; //$NON-NLS-1$
Column relParentKeyColumn = new ColumnImpl();
relParentKeyColumn.setName(relParentColumnName);
relParentKeyColumn.setDataType(new DataTypeImpl("string", XML_SCHEMA_URI)); //$NON-NLS-1$
relParentKeyColumn.setRole(XMLRequestResponseExtensionManagerImpl.DATA_ROLE);
relParentKeyColumn.setOutputXPath(relParentOutputXPath);
relParentKeyColumn.setIsForeignKey(true);
relTable.addColumn(relParentKeyColumn);
String relChildColumnName = child.getName() + "_" + MMID; //$NON-NLS-1$
String relChildOutputXPath = child.getOutputXPath() + "/@com.metamatrix.xml.xpathpart"; //$NON-NLS-1$
Column relChildKeyColumn = new ColumnImpl();
relChildKeyColumn.setName(relChildColumnName);
relChildKeyColumn.setDataType(new DataTypeImpl("string", XML_SCHEMA_URI)); //$NON-NLS-1$
relChildKeyColumn.setRole(XMLRequestResponseExtensionManagerImpl.DATA_ROLE);
relChildKeyColumn.setOutputXPath(relChildOutputXPath);
relChildKeyColumn.setIsForeignKey(true);
relTable.addColumn(relChildKeyColumn);
tables.put(relTable.getName(), new SOAPTableImpl(relTable, false, null, null));
break;
case Relationship.KEY_IN_PARENT_MULTIPLE:
case Relationship.MERGE_IN_PARENT_MULTIPLE:
case Relationship.MERGE_IN_PARENT_SINGLE:
case Relationship.UNBOUNDED:
default:
// should probably throw something here
// since these relationships would indicate an
// error in the schema processing
}
}
private String getChildKeyColumnXPath( Table parent,
Table child ) {
Relationship relationship = ((TableImpl)child).getRelationObjectToParent(parent);
StringBuffer result = new StringBuffer();
result.append(relationship.getParentRelativeXpath());
result.append("/@com.metamatrix.xml.xpathpart"); //$NON-NLS-1$
return result.toString();
}
}