/*
* 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.xml.aspects.sql;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.mapping.Mapping;
import org.eclipse.emf.mapping.MappingRoot;
import org.eclipse.xsd.XSDComponent;
import org.eclipse.xsd.XSDElementDeclaration;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.container.Container;
import org.teiid.designer.core.index.IndexConstants;
import org.teiid.designer.core.metamodel.aspect.AspectManager;
import org.teiid.designer.core.metamodel.aspect.MetamodelEntity;
import org.teiid.designer.core.metamodel.aspect.sql.SqlAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlTableAspect;
import org.teiid.designer.core.resource.EmfResource;
import org.teiid.designer.core.types.DatatypeConstants;
import org.teiid.designer.core.types.DatatypeManager;
import org.teiid.designer.core.util.ModelContents;
import org.teiid.designer.metadata.runtime.MetadataConstants;
import org.teiid.designer.metamodels.transformation.MappingClassColumn;
import org.teiid.designer.metamodels.transformation.TreeMappingRoot;
import org.teiid.designer.metamodels.xml.XmlDocument;
import org.teiid.designer.metamodels.xml.XmlElement;
import org.teiid.designer.metamodels.xml.XmlRoot;
import org.teiid.designer.xml.PluginConstants;
/**
* XmlContainerNodeSqlAspect
*
* @since 8.0
*/
public class XmlElementSqlAspect extends AbstractXmlDocumentEntitySqlAspect implements SqlColumnAspect {
final static boolean SELECTABLE = true;
final static boolean UPDATABLE = false;
final static boolean AUTO_INCREMENT = false;
final static boolean CASE_SENSITIVE = false;
final static boolean SIGNED = false;
final static boolean CURRENCY = false;
final static boolean FIXED_LENGTH = false;
final static boolean TRANSFORMATION_INPUT_PARAMETER = false;
final static int SEARCH_TYPE = MetadataConstants.SEARCH_TYPES.SEARCHABLE; // searcheable
final static String DEFAULT_VALUE = null;
final static Object MIN_VALUE = null;
final static Object MAX_VALUE = null;
final static int LENGTH = 0;
final static int SCALE = 0;
final static int NULL_TYPE = MetadataConstants.NULL_TYPES.NULLABLE; // nullable
final static String FORMAT = null;
final static int PRECISION = 0;
final static int CHAR_OCTET_LENGTH = 0;
final static int POSITION = 0;
final static int RADIX = 0;
final static int NULL_VALUES = 0;
final static int DISTINCT_VALUES = 0;
// map between XmlElement and MappingClassColumn
private Map elementMap = null;
private Set elementFullNames;
private String currentDocumentName;
/**
* Construct an instance of XmlContainerNodeSqlAspect.
*/
public XmlElementSqlAspect( final MetamodelEntity entity ) {
super(entity);
}
/**
* @see org.teiid.designer.core.metamodel.aspect.sql.SqlAspect#isRecordType(char)
*/
@Override
public boolean isRecordType( final char recordType ) {
return (recordType == IndexConstants.RECORD_TYPE.COLUMN);
}
/**
* @see org.teiid.designer.core.metamodel.aspect.sql.SqlAspect#getName(org.eclipse.emf.ecore.EObject)
*/
@Override
public String getName( final EObject eObject ) {
CoreArgCheck.isInstanceOf(XmlElement.class, eObject);
IPath path = new Path(getShortName(eObject));
EObject parent = eObject.eContainer();
SqlAspect parentAspect = AspectManager.getSqlAspect(parent);
while (parentAspect != null) {
if (parent instanceof XmlDocument) {
// XmlDocumentSqlAspect now implements SqlTableAspect AND SqlColumnAspect
break;
}
if (parentAspect instanceof SqlColumnAspect) {
String name = null;
if (parentAspect instanceof AbstractXmlDocumentEntitySqlAspect) {
name = ((AbstractXmlDocumentEntitySqlAspect)parentAspect).getShortName(parent);
} else {
name = parentAspect.getName(parent);
}
path = new Path("").append(name).append(path); //$NON-NLS-1$
} else if (parentAspect instanceof SqlTableAspect) {
break;
}
// Walk up to the parent ...
parent = parent.eContainer();
parentAspect = AspectManager.getSqlAspect(parent);
}
return path.toString().replace(IPath.SEPARATOR, '.');
}
@Override
protected String getShortName( final EObject eObject ) {
CoreArgCheck.isInstanceOf(XmlElement.class, eObject);
return ((XmlElement)eObject).getName();
}
@Override
protected String getParentFullName( EObject eObject ) {
EObject parent = eObject.eContainer();
if (parent != null) {
SqlAspect parentAspect = AspectManager.getSqlAspect(parent);
while (parentAspect != null) {
if (parentAspect instanceof SqlTableAspect) {
return parentAspect.getFullName(parent);
}
parent = parent.eContainer();
if (parent != null) {
parentAspect = AspectManager.getSqlAspect(parent);
} else {
return null;
}
}
}
return null;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getCharOctetLength(org.eclipse.emf.ecore.EObject)
*/
@Override
public int getCharOctetLength( EObject eObject ) {
return CHAR_OCTET_LENGTH;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getDatatype(org.eclipse.emf.ecore.EObject)
*/
@Override
public EObject getDatatype( EObject eObject ) {
CoreArgCheck.isInstanceOf(XmlElement.class, eObject);
XmlElement xmlElement = (XmlElement)eObject;
if (elementMap == null) {
populateMappingInfo(xmlElement);
}
Object lookupObj = elementMap.get(xmlElement);
if (lookupObj == null
&& (elementFullNames.contains(this.getFullName(xmlElement)) || !currentDocumentName.equals(getXmlDocument(xmlElement).getName()))) {
populateMappingInfo(xmlElement);
lookupObj = elementMap.get(xmlElement);
}
Container cntr = ModelerCore.getContainer(eObject);
if (lookupObj != null) {
CoreArgCheck.isInstanceOf(MappingClassColumn.class, lookupObj, null);
MappingClassColumn mappingColumn = (MappingClassColumn)lookupObj;
EObject type = mappingColumn.getType();
return resolveWhenProxy(type, cntr);
}
try {
final XSDComponent xsdComp = xmlElement.getXsdComponent();
if (xsdComp instanceof XSDElementDeclaration) {
final EObject type = ((XSDElementDeclaration)xsdComp).getTypeDefinition();
if (type != null) {
return resolveWhenProxy(type, cntr);
}
}
return ModelerCore.getDatatypeManager(eObject).getBuiltInDatatype(DatatypeConstants.BuiltInNames.STRING);
} catch (Throwable e) {
}// ignore
return null;
}
private EObject resolveWhenProxy( EObject e,
ResourceSet resolveContext ) {
EObject resolvedEObject = e;
if (e != null && e.eIsProxy()) {
resolvedEObject = EcoreUtil.resolve(e, resolveContext);
if (resolvedEObject.eIsProxy()) {
String msg = PluginConstants.Util.getString("XmlElementSqlAspect.Unable_to_resolve_proxy_with_uri", ((InternalEObject)e).eProxyURI()); //$NON-NLS-1$
PluginConstants.Util.log(IStatus.ERROR, msg);
}
}
return resolvedEObject;
}
/**
* @see org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getNativeType(org.eclipse.emf.ecore.EObject)
* @since 4.2
*/
@Override
public String getNativeType( EObject eObject ) {
return null;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getDatatypeName(org.eclipse.emf.ecore.EObject)
*/
@Override
public String getDatatypeName( EObject eObject ) {
final EObject datatype = getDatatype(eObject);
final DatatypeManager dtMgr = ModelerCore.getDatatypeManager(eObject, true);
final String dtName = dtMgr.getName(datatype);
return dtName == null ? DatatypeConstants.BuiltInNames.STRING : dtName;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getDatatypeObjectID(org.eclipse.emf.ecore.EObject)
*/
@Override
public String getDatatypeObjectID( EObject eObject ) {
EObject datatype = getDatatype(eObject);
try {
if (datatype == null) {
datatype = ModelerCore.getWorkspaceDatatypeManager().getBuiltInDatatype(DatatypeConstants.BuiltInNames.STRING);
}
} catch (Throwable e) {
}// ignore
final DatatypeManager dtMgr = ModelerCore.getDatatypeManager(eObject, true);
final String uuid = dtMgr.getUuidString(datatype);
return uuid == null ? "" : uuid; //$NON-NLS-1$
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getDefaultValue(org.eclipse.emf.ecore.EObject)
*/
@Override
public String getDefaultValue( EObject eObject ) {
return DEFAULT_VALUE;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getFormat(org.eclipse.emf.ecore.EObject)
*/
@Override
public String getFormat( EObject eObject ) {
return FORMAT;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getLength(org.eclipse.emf.ecore.EObject)
*/
@Override
public int getLength( EObject eObject ) {
return LENGTH;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getMaxValue(org.eclipse.emf.ecore.EObject)
*/
@Override
public Object getMaxValue( EObject eObject ) {
return MAX_VALUE;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getMinValue(org.eclipse.emf.ecore.EObject)
*/
@Override
public Object getMinValue( EObject eObject ) {
return MIN_VALUE;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getNullType(org.eclipse.emf.ecore.EObject)
*/
@Override
public int getNullType( EObject eObject ) {
return NULL_TYPE;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getPosition(org.eclipse.emf.ecore.EObject)
*/
@Override
public int getPosition( EObject eObject ) {
return POSITION;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getPrecision(org.eclipse.emf.ecore.EObject)
*/
@Override
public int getPrecision( EObject eObject ) {
return PRECISION;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getRadix(org.eclipse.emf.ecore.EObject)
*/
@Override
public int getRadix( EObject eObject ) {
return RADIX;
}
/**
* @see org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getDistinctValues(org.eclipse.emf.ecore.EObject)
* @since 4.3
*/
@Override
public int getDistinctValues( EObject eObject ) {
return DISTINCT_VALUES;
}
/**
* @see org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getNullValues(org.eclipse.emf.ecore.EObject)
* @since 4.3
*/
@Override
public int getNullValues( EObject eObject ) {
return NULL_VALUES;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getRuntimeType(org.eclipse.emf.ecore.EObject)
*/
@Override
public String getRuntimeType( EObject eObject ) {
String runtimeType = null;
EObject datatype = getDatatype(eObject);
if (datatype != null) {
runtimeType = ModelerCore.getDatatypeManager(eObject, true).getRuntimeTypeName(datatype);
}
if (runtimeType == null) {
runtimeType = DatatypeConstants.RuntimeTypeNames.STRING;
}
return runtimeType;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getScale(org.eclipse.emf.ecore.EObject)
*/
@Override
public int getScale( EObject eObject ) {
return SCALE;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#getSearchType(org.eclipse.emf.ecore.EObject)
*/
@Override
public int getSearchType( EObject eObject ) {
return SEARCH_TYPE;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#isAutoIncrementable(org.eclipse.emf.ecore.EObject)
*/
@Override
public boolean isAutoIncrementable( EObject eObject ) {
return AUTO_INCREMENT;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#isCaseSensitive(org.eclipse.emf.ecore.EObject)
*/
@Override
public boolean isCaseSensitive( EObject eObject ) {
return CASE_SENSITIVE;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#isCurrency(org.eclipse.emf.ecore.EObject)
*/
@Override
public boolean isCurrency( EObject eObject ) {
return CURRENCY;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#isFixedLength(org.eclipse.emf.ecore.EObject)
*/
@Override
public boolean isFixedLength( EObject eObject ) {
return FIXED_LENGTH;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#isSelectable(org.eclipse.emf.ecore.EObject)
*/
@Override
public boolean isSelectable( EObject eObject ) {
return SELECTABLE;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#isSigned(org.eclipse.emf.ecore.EObject)
*/
@Override
public boolean isSigned( EObject eObject ) {
return SIGNED;
}
/**
* @see org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#isTranformationInputParameter(org.eclipse.emf.ecore.EObject)
* @since 4.2
*/
@Override
public boolean isTranformationInputParameter( EObject eObject ) {
CoreArgCheck.isInstanceOf(XmlElement.class, eObject);
final XmlElement element = (XmlElement)eObject;
if (element instanceof XmlRoot) {
return false;
}
final XmlDocument doc = getDocParent(element);
final XmlElement parent = getElementParent(element);
if (doc == null || parent == null) {
return false;
}
Resource eResource = element.eResource();
if (eResource instanceof EmfResource) {
EmfResource emfResource = (EmfResource)eResource;
ModelContents contents = emfResource.getModelContents();
if (contents != null) {
for (final Iterator mappings = contents.getTransformations(doc).iterator(); mappings.hasNext();) {
final TreeMappingRoot tmr = (TreeMappingRoot)mappings.next();
if (tmr.getOutputs().contains(parent)) {
final Iterator nested = tmr.getNested().iterator();
while (nested.hasNext()) {
final Mapping mapping = (Mapping)nested.next();
if (mapping.getOutputs().contains(element)) {
if (mapping.getInputs().size() == 0) {
return false;
}
Iterator i = mapping.getInputs().iterator();
while (i.hasNext()) {
MappingClassColumn column = (MappingClassColumn)i.next();
SqlAspect aspect = AspectManager.getSqlAspect(column);
if (!(aspect instanceof SqlColumnAspect)) {
return false;
}
if (!((SqlColumnAspect)aspect).isTranformationInputParameter(column)) {
return false;
}
}
return true;
}
}
}
}
}
}
return false;
}
private XmlDocument getDocParent( final XmlElement child ) {
if (child == null) {
return null;
}
EObject parent = child.eContainer();
while (parent != null) {
if (parent instanceof XmlDocument) {
return (XmlDocument)parent;
}
parent = parent.eContainer();
}
return null;
}
private XmlElement getElementParent( final XmlElement child ) {
if (child == null) {
return null;
}
EObject parent = child.eContainer();
while (parent != null) {
if (parent instanceof XmlElement) {
return (XmlElement)parent;
}
parent = parent.eContainer();
}
return null;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#isUpdatable(org.eclipse.emf.ecore.EObject)
*/
@Override
public boolean isUpdatable( EObject eObject ) {
return UPDATABLE;
}
/**
* @see org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#canSetDatatype()
* @since 4.2
*/
@Override
public boolean canSetDatatype() {
return false;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#setDatatype(org.eclipse.emf.ecore.EObject, org.teiid.designer.metamodels.core.Datatype)
*/
@Override
public void setDatatype( EObject eObject,
EObject datatype ) {
throw new UnsupportedOperationException(
PluginConstants.Util.getString("XmlElementSqlAspect.Datatype_cannot_be_set_on_an_XMLElement_1")); //$NON-NLS-1$
}
/**
* @see org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#canSetLength()
* @since 4.2
*/
@Override
public boolean canSetLength() {
return false;
}
/**
* @see org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#setLength(org.eclipse.emf.ecore.EObject, int)
*/
@Override
public void setLength( EObject eObject,
int length ) {
throw new UnsupportedOperationException(
PluginConstants.Util.getString("XmlElementSqlAspect.Length_cannot_be_set_on_an_XMLElement_2")); //$NON-NLS-1$
}
/**
* @see org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#canSetNullType()
* @since 4.2
*/
@Override
public boolean canSetNullType() {
return false;
}
/**
* @see org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#setNullType(org.eclipse.emf.ecore.EObject, int)
*/
@Override
public void setNullType( EObject eObject,
int nullType ) {
throw new UnsupportedOperationException(
PluginConstants.Util.getString("XmlElementSqlAspect.NullType_cannot_be_set_on_an_XMLElement_3")); //$NON-NLS-1$
}
Map getMappingInfo( EObject xmlEntity ) {
if (this.elementMap != null) {
return this.elementMap;
}
populateMappingInfo(xmlEntity);
return this.elementMap;
}
private void populateMappingInfo( EObject xmlEntity ) {
Resource resource = xmlEntity.eResource();
// model contents for this resource
ModelContents mdlContents = new ModelContents(resource);
XmlDocument document = getXmlDocument(xmlEntity);
currentDocumentName = document.getName();
// fill the map with element to its mappingClass column value
this.elementMap = new HashMap();
this.elementFullNames = new HashSet();
// get the mapping root associated with the transformation
Iterator rootIter = mdlContents.getTransformations(document).iterator();
while (rootIter.hasNext()) {
MappingRoot mappingRoot = (MappingRoot)rootIter.next();
// if there is a mapping root
if (mappingRoot != null && mappingRoot instanceof TreeMappingRoot) {
Iterator mappingIter = mappingRoot.getNested().iterator();
while (mappingIter.hasNext()) {
Mapping nestedMapping = (Mapping)mappingIter.next();
// mapping Class columns
List inputs = nestedMapping.getInputs();
// xml elements
List outputs = nestedMapping.getOutputs();
if (!outputs.isEmpty() && !inputs.isEmpty()) {
Object output = outputs.iterator().next();
Object input = inputs.iterator().next();
elementMap.put(output, input);
if (output instanceof XmlElement) {
elementFullNames.add(this.getFullName((EObject)output));
}
}
}
}
}
}
private XmlDocument getXmlDocument( EObject xmlElement ) {
EObject container = xmlElement.eContainer();
EObject document = null;
// append parent information in front of the eObject name
while (container != null) {
document = container;
container = container.eContainer();
}
CoreArgCheck.isInstanceOf(XmlDocument.class, document, null);
return (XmlDocument)document;
}
/*
* @See org.teiid.designer.core.metamodel.aspect.sql.SqlAspect#updateObject(org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject)
*/
@Override
public void updateObject( EObject targetObject,
EObject sourceObject ) {
}
/**
* @see org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect#isDatatypeFeature(org.eclipse.emf.ecore.EObject,
* org.eclipse.emf.ecore.EStructuralFeature)
*/
@Override
public boolean isDatatypeFeature( final EObject eObject,
final EStructuralFeature eFeature ) {
// there is no datattype feature on xml attributes
return false;
}
}