/*
* 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.webservice.gen;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xsd.XSDComponent;
import org.eclipse.xsd.XSDElementDeclaration;
import org.eclipse.xsd.XSDNamedComponent;
import org.teiid.core.designer.ModelerCoreException;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.designer.compare.selector.ModelSelector;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.resource.EmfResource;
import org.teiid.designer.core.util.ModelContents;
import org.teiid.designer.core.util.ModelResourceContainerFactory;
import org.teiid.designer.core.util.ModelVisitor;
import org.teiid.designer.core.util.ModelVisitorProcessor;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
import org.teiid.designer.mapping.factory.ITreeToRelationalMapper;
import org.teiid.designer.mapping.factory.MappingClassBuilderStrategy;
import org.teiid.designer.mapping.factory.MappingClassFactory;
import org.teiid.designer.mapping.factory.ModelMapperFactory;
import org.teiid.designer.metamodels.transformation.SqlTransformation;
import org.teiid.designer.metamodels.transformation.SqlTransformationMappingRoot;
import org.teiid.designer.metamodels.transformation.TransformationContainer;
import org.teiid.designer.metamodels.transformation.TransformationFactory;
import org.teiid.designer.metamodels.webservice.Interface;
import org.teiid.designer.metamodels.webservice.Operation;
import org.teiid.designer.metamodels.webservice.Output;
import org.teiid.designer.metamodels.webservice.SampleMessages;
import org.teiid.designer.metamodels.webservice.WebServiceComponent;
import org.teiid.designer.metamodels.webservice.WebServiceFactory;
import org.teiid.designer.metamodels.xml.XmlDocument;
import org.teiid.designer.metamodels.xml.XmlDocumentBuilderImpl;
import org.teiid.designer.metamodels.xml.XmlDocumentFactory;
import org.teiid.designer.metamodels.xml.XmlRoot;
import org.teiid.designer.transformation.util.TransformationHelper;
import org.teiid.designer.webservice.IWebServiceXmlDocumentGenerator;
import org.teiid.designer.webservice.WebServicePlugin;
import org.teiid.designer.webservice.util.WebServiceUtil;
/**
* @since 8.0
*/
public class BasicWebServiceXmlDocumentGenerator implements IWebServiceXmlDocumentGenerator {
private Resource xmlDocResource;
private final List webServiceComponents;
private boolean reuseExistingDocuments;
private ModelSelector webServiceModelSelector;
/**
* @since 4.2
*/
public BasicWebServiceXmlDocumentGenerator() {
super();
this.webServiceComponents = new ArrayList();
}
/**
* @see org.teiid.designer.webservice.IWebServiceXmlDocumentGenerator#addWebServiceComponent(org.teiid.designer.metamodels.webservice.WebServiceComponent)
* @since 4.2
*/
@Override
public void addWebServiceComponent( WebServiceComponent webServiceComponent ) {
CoreArgCheck.isNotNull(webServiceComponent);
if (!this.webServiceComponents.contains(webServiceComponent)) {
this.webServiceComponents.add(webServiceComponent);
}
}
/**
* @see org.teiid.designer.webservice.IWebServiceXmlDocumentGenerator#addWebServiceComponents(java.util.List)
* @since 4.2
*/
@Override
public void addWebServiceComponents( List webServiceComponents ) {
CoreArgCheck.isNotNull(webServiceComponents);
final Iterator iter = webServiceComponents.iterator();
while (iter.hasNext()) {
final WebServiceComponent webServiceComponent = (WebServiceComponent)iter.next();
if (webServiceComponent != null && !this.webServiceComponents.contains(webServiceComponent)) {
this.webServiceComponents.add(webServiceComponent);
}
}
}
/**
* @see org.teiid.designer.webservice.IWebServiceXmlDocumentGenerator#getWebServiceModelSelector()
* @since 4.2
*/
@Override
public ModelSelector getWebServiceModelSelector() {
return this.webServiceModelSelector;
}
/**
* @see org.teiid.designer.webservice.IWebServiceXmlDocumentGenerator#setWebServiceModelSelector(org.teiid.designer.compare.selector.ModelSelector)
* @since 4.2
*/
@Override
public void setWebServiceModelSelector( ModelSelector wsModelSelector ) {
this.webServiceModelSelector = wsModelSelector;
}
/**
* @see org.teiid.designer.webservice.IWebServiceXmlDocumentGenerator#getWebServiceComponents()
* @since 4.2
*/
@Override
public List getWebServiceComponents() {
return this.webServiceComponents;
}
/**
* @see org.teiid.designer.webservice.IWebServiceXmlDocumentGenerator#setXmlDocumentResource(org.eclipse.emf.ecore.resource.Resource)
* @since 4.2
*/
@Override
public void setXmlDocumentResource( Resource wsModel ) {
CoreArgCheck.isNotNull(wsModel);
this.xmlDocResource = wsModel;
}
/**
* @see org.teiid.designer.webservice.IWebServiceXmlDocumentGenerator#getXmlDocumentResource()
* @since 4.2
*/
@Override
public Resource getXmlDocumentResource() {
return this.xmlDocResource;
}
/**
* @see org.teiid.designer.webservice.IWebServiceXmlDocumentGenerator#generate(org.eclipse.core.runtime.IProgressMonitor)
* @since 4.2
*/
@Override
public IStatus generate( IProgressMonitor monitor ) {
final List problems = new ArrayList();
if (this.getXmlDocumentResource() == null) {
final String msg = WebServicePlugin.Util.getString("BasicWebServiceXmlDocumentGenerator.NoXmlDocumentModelSpecified"); //$NON-NLS-1$
problems.add(new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, 0, msg, null));
} else {
doGenerate(monitor, problems);
}
// Convert the problems to a status
IStatus result = null;
if (problems.size() == 0) {
final String msg = WebServicePlugin.Util.getString("BasicWebServiceXmlDocumentGenerator.GenerationOfXmlDocumentsSucceeded"); //$NON-NLS-1$
result = new Status(IStatus.OK, WebServicePlugin.PLUGIN_ID, 0, msg, null);
} else if (problems.size() == 1) {
result = (IStatus)problems.get(0);
} else {
// Iterate over the problems and find the number of warnings and errors ...
int errors = 0;
int warnings = 0;
final Iterator iter = problems.iterator();
while (iter.hasNext()) {
final IStatus status = (IStatus)iter.next();
switch (status.getSeverity()) {
case IStatus.ERROR: {
++errors;
break;
}
case IStatus.WARNING: {
++warnings;
break;
}
}
}
final Object[] params = new Object[] {new Integer(errors), new Integer(warnings)};
final String msg = WebServicePlugin.Util.getString("BasicWebServiceXmlDocumentGenerator.GeneratedXmlDocumentWithErrorsAndWarnings", params); //$NON-NLS-1$
final IStatus[] children = (IStatus[])problems.toArray(new IStatus[problems.size()]);
result = new MultiStatus(WebServicePlugin.PLUGIN_ID, 0, children, msg, null);
}
return result;
}
/**
* @see org.teiid.designer.webservice.IWebServiceXmlDocumentGenerator#generate(org.eclipse.core.runtime.IProgressMonitor,
* java.util.List)
* @since 4.2
*/
@Override
public void generate( IProgressMonitor monitor,
List problems ) {
doGenerate(monitor, problems);
}
// ========================================================================================================
// Overridable methods
// ========================================================================================================
protected void doGenerate( IProgressMonitor monitor,
final List problems ) {
// Create the correct visitor for the desired version ...
final List outputs = new ArrayList();
final WebServiceVisitor visitor = new WebServiceVisitor(outputs);
// Walk the objects and find all of the Output objects ...
final ModelVisitorProcessor processor = new ModelVisitorProcessor(visitor);
try {
processor.walk(this.webServiceComponents, ModelVisitorProcessor.DEPTH_INFINITE);
} catch (ModelerCoreException e) {
// handle the exception
}
ModelContents wsContents = null;
try {
wsContents = this.getWebServiceModelSelector().getModelContents();
} catch (ModelWorkspaceException err) {
String message = WebServicePlugin.Util.getString("BasicWebServiceXmlDocumentGenerator.UnableToGetWebServiceContents"); //$NON-NLS-1$
final IStatus status = new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, 0, message, err);
problems.add(status);
}
// Now, iterate over each of the Output objects and generate an XmlDocument ...
if (wsContents != null && outputs.size() != 0) {
final List docs = new ArrayList();
final ModelContents xmlContents = doGetModelContents();
final Iterator iter = outputs.iterator();
// EObject obj = null;
while (iter.hasNext()) {
final Output output = (Output)iter.next();
final XmlDocument xmlDoc = doGenerateXmlDocument(output, monitor, problems, docs, xmlContents);
if (xmlDoc != null) {
doGenerateTransformation(output, xmlDoc, monitor, problems, wsContents);
}
// Check for cancellation ...
if (monitor.isCanceled()) {
return;
}
// obj = output;
}
// if ( obj != null ) {
// try {
// obj.eResource().save(System.out, new HashMap());
// } catch (IOException err1) {
// err1.printStackTrace();
// }
// }
}
}
protected String computeXmlDocumentName( Output output ) {
StringBuffer sb = new StringBuffer();
sb.append(output.getOperation().getInterface().getName());
sb.append('_');
sb.append(output.getOperation().getName());
sb.append('_');
sb.append(output.getName());
return sb.toString();
}
protected String getFullName( EObject output ) {
return ModelerCore.getModelEditor().getModelRelativePathIncludingModel(output).toString();
}
protected XmlDocument doGenerateXmlDocument( Output output,
IProgressMonitor monitor,
List problems,
List newDocs,
ModelContents contents ) {
// Check for cancellation ...
if (monitor.isCanceled()) {
return null;
}
// Obtain the XSD type from the output ...
final XSDElementDeclaration elementDecl = output.getContentElement();
if (elementDecl == null) {
return null; // can't generate at all
}
if (elementDecl.getURI() == null) {
return null; // can't really generate
}
XmlDocument xmlDoc = null;
if (reuseExistingDocuments) {
// See if there is already an existing XML document ...
final Iterator iter = this.xmlDocResource.getContents().iterator();
while (iter.hasNext()) {
final EObject root = (EObject)iter.next();
if (root instanceof XmlDocument) {
final XmlDocument existingDoc = (XmlDocument)root;
final XmlRoot rootElement = existingDoc.getRoot();
final XSDComponent rootElementXsdComp = rootElement.getXsdComponent();
if (rootElementXsdComp instanceof XSDElementDeclaration) {
final XSDNamedComponent namedComponent = (XSDElementDeclaration)rootElementXsdComp;
if (elementDecl.getURI().equals(namedComponent.getURI())) {
// The URIs of the element declarations are the same, so they must be the same schemas
xmlDoc = existingDoc;
break;
}
}
}
}
}
if (monitor.isCanceled()) {
return xmlDoc;
}
if (xmlDoc == null) {
// Generate the XML document ...
final XmlDocumentBuilderImpl builder = new XmlDocumentBuilderImpl();
final XmlDocumentFactory factory = XmlDocumentFactory.eINSTANCE;
try {
// Create the document ...
xmlDoc = factory.createXmlDocument();
final String docName = computeXmlDocumentName(output);
xmlDoc.setName(docName);
this.xmlDocResource.getContents().add(xmlDoc);
newDocs.add(xmlDoc); // add the document to the model ...
// Create the root ...
XmlRoot docRoot = factory.createXmlRoot();
docRoot.setName(elementDecl.getName());
docRoot.setXsdComponent(elementDecl);
xmlDoc.setRoot(docRoot);
// Build the rest of the document ...
builder.buildDocument(docRoot, monitor);
final ITreeToRelationalMapper mapper = ModelMapperFactory.createModelMapper(xmlDoc);
if (mapper != null) {
final MappingClassFactory mcFactory = new MappingClassFactory(mapper);
mcFactory.generateMappingClasses(docRoot, MappingClassBuilderStrategy.iterationStrategy, true);
}
} catch (Exception e) {
final Object[] params = new Object[] {getFullName(output)};
String message = WebServicePlugin.Util.getString("BasicWebServiceXmlDocumentGenerator.ErrorWhileGeneratingXmlDocumentForWsModel", params); //$NON-NLS-1$
final IStatus status = new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, 0, message, e);
problems.add(status);
}
}
if (xmlDoc != null) {
// Set the reference on the output ...
output.setXmlDocument(xmlDoc);
return xmlDoc;
}
return xmlDoc;
}
protected void doGenerateTransformation( final Output output,
final XmlDocument xmlDoc,
final IProgressMonitor monitor,
final List problems,
final ModelContents wsContents ) {
if (output == null || xmlDoc == null) {
return;
}
// Find the corresponding Input ...
final Operation op = output.getOperation();
if (op == null) {
return;
}
// Generate the transformation SQL ...
final WebServiceUtil util = new WebServiceUtil();
final String sql = util.generateTransformationSql(output, xmlDoc);
if (sql != null) {
// Find the mapping root ...
SqlTransformationMappingRoot mappingRoot = (SqlTransformationMappingRoot)TransformationHelper.getTransformationMappingRoot(op,
false,
false);
if (mappingRoot == null) {
mappingRoot = TransformationFactory.eINSTANCE.createSqlTransformationMappingRoot();
try {
TransformationContainer tc = ModelResourceContainerFactory.getTransformationContainer(op.eResource(), true);
mappingRoot.setTarget(op);
ModelerCore.getModelEditor().addValue(mappingRoot, op, mappingRoot.getOutputs());
ModelerCore.getModelEditor().addValue(tc, mappingRoot, tc.getTransformationMappings());
} catch (ModelerCoreException err) {
ModelerCore.Util.log(IStatus.ERROR,
err,
WebServicePlugin.Util.getString("BasicWebServiceXmlDocumentGenerator.ErrorWhileGeneratingTransformationsForWsModel", op)); //$NON-NLS-1$
}
}
// Set the transformation for the operation ...
// Note, use the explicit methods rather than TransformationHelper,
// which presumes the existance of a ModelResource ...
SqlTransformation sqlTransformation = (SqlTransformation)TransformationHelper.getMappingHelper(mappingRoot);
if (sqlTransformation == null) {
sqlTransformation = TransformationFactory.eINSTANCE.createSqlTransformation();
mappingRoot.setHelper(sqlTransformation);
}
// Create Nested SqlTransformation for User SQL
SqlTransformation userSqlTrans = TransformationHelper.getUserSqlTransformation(mappingRoot);
if (userSqlTrans == null) {
userSqlTrans = TransformationFactory.eINSTANCE.createSqlTransformation();
userSqlTrans.setNestedIn(sqlTransformation);
}
userSqlTrans.setSelectSql(sql);
// Add the XML document as an input to the mappingRoot ...
mappingRoot.getInputs().add(xmlDoc);
if (!mappingRoot.getOutputs().contains(op)) {
mappingRoot.getOutputs().add(op);
}
// Add the nested mapping between the SELECT's "xml" and the
// Output's sample messages (represents the ResultSetColumn)
SampleMessages resultSetColumn = output.getSamples();
if (resultSetColumn == null) {
// Create it since it's not there ...
resultSetColumn = WebServiceFactory.eINSTANCE.createSampleMessages();
output.setSamples(resultSetColumn);
}
// final Mapping nested = MappingFactory.eINSTANCE.createMapping();
// nested.getOutputs().add(resultSetColumn);
// //nested.getInputs().add(???); // nothing to add as input, since it's the sole column in the result set
// nested.setNestedIn(mappingRoot);
}
}
protected ModelContents doGetModelContents() {
final ModelContents contents = this.xmlDocResource instanceof EmfResource ? ((EmfResource)this.xmlDocResource).getModelContents() : new ModelContents(
this.xmlDocResource);
return contents;
}
// ========================================================================================================
// XmlDocument Generator
// ========================================================================================================
protected class WebServiceVisitor implements ModelVisitor {
private final List outputs;
protected WebServiceVisitor( final List outputs ) {
this.outputs = outputs;
}
@Override
public boolean visit( EObject object ) {
if (object instanceof Output) {
this.outputs.add(object);
return false;
}
if (object instanceof Interface) {
return true;
}
if (object instanceof Operation) {
return true;
}
return false;
}
@Override
public boolean visit( Resource resource ) {
return true;
}
}
}