/*
* 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.util;
import java.io.File;
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 java.util.Set;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.URI;
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.teiid.core.designer.ModelerCoreException;
import org.teiid.core.designer.PluginUtil;
import org.teiid.core.designer.util.I18nUtil;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.builder.ModelBuildUtil;
import org.teiid.designer.core.container.Container;
import org.teiid.designer.core.metamodel.aspect.sql.SqlAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper;
import org.teiid.designer.core.resource.xmi.MtkXmiResourceImpl;
import org.teiid.designer.core.util.ModelContents;
import org.teiid.designer.core.util.NewModelObjectHelperManager;
import org.teiid.designer.core.validation.ValidationResultImpl;
import org.teiid.designer.core.validation.rules.CoreValidationRulesUtil;
import org.teiid.designer.core.workspace.ModelProject;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
import org.teiid.designer.core.workspace.ModelWorkspaceItem;
import org.teiid.designer.metamodels.core.ModelAnnotation;
import org.teiid.designer.metamodels.core.ModelType;
import org.teiid.designer.metamodels.webservice.Input;
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.WebServicePackage;
import org.teiid.designer.metamodels.webservice.aspects.sql.InputAspect;
import org.teiid.designer.metamodels.webservice.aspects.sql.InterfaceAspect;
import org.teiid.designer.metamodels.webservice.aspects.sql.OperationAspect;
import org.teiid.designer.metamodels.webservice.aspects.sql.OutputAspect;
import org.teiid.designer.metamodels.xml.XmlDocument;
import org.teiid.designer.metamodels.xml.XmlElement;
import org.teiid.designer.metamodels.xml.XmlSequence;
import org.teiid.designer.query.sql.lang.IQuery;
import org.teiid.designer.transformation.util.SqlMappingRootCache;
import org.teiid.designer.transformation.util.TransformationHelper;
import org.teiid.designer.transformation.util.TransformationMappingHelper;
import org.teiid.designer.transformation.util.TransformationSqlHelper;
import org.teiid.designer.type.IDataTypeManagerService;
import org.teiid.designer.type.IDataTypeManagerService.DataTypeName;
import org.teiid.designer.webservice.WebServicePlugin;
import org.teiid.designer.webservice.procedure.XsdInstanceNode;
/**
* Build XSD models from a set of Relational Entities.
*
* @since 8.0
*/
public class WebServiceBuilderHelper {
/** Properties key prefix. */
private static final String PREFIX = I18nUtil.getPropertyPrefix(WebServiceBuilderHelper.class);
private static final String FILE_EXT = ".xmi"; //$NON-NLS-1$
// Used to enable Unit Testing.
public static boolean HEADLESS = false;
private static org.eclipse.emf.common.command.Command getInterfaceDescriptor( final Resource resource ) {
org.eclipse.emf.common.command.Command interfaceDescriptor = null;
// ------------------------------------------------
// Get the Descriptor for InterfaceAspect
// ------------------------------------------------
// Get the valid descriptors that can be added under the targetEObject
Collection descriptors = null;
try {
descriptors = ModelerCore.getModelEditor().getNewRootObjectCommands(resource);
} catch (final ModelerCoreException e) {
final String message = getString("getInterfaceDescriptor.errMsg"); //$NON-NLS-1$
WebServicePlugin.Util.log(IStatus.ERROR, e, message);
return null;
}
// Use the first InterfaceAspect found
final Iterator iter = descriptors.iterator();
while (iter.hasNext()) {
interfaceDescriptor = (org.eclipse.emf.common.command.Command)iter.next();
final EObject eObj = (EObject)interfaceDescriptor.getResult().iterator().next();
// If the descriptor is a ColumnAspect, stop
final SqlAspect aspect = SqlAspectHelper.getSqlAspect(eObj);
if (aspect instanceof InterfaceAspect) break;
}
return interfaceDescriptor;
}
private static org.eclipse.emf.common.command.Command getOperationDescriptor( final EObject targetEObject ) {
org.eclipse.emf.common.command.Command operationDescriptor = null;
// ------------------------------------------------
// Get the Descriptor for OperationAspect
// ------------------------------------------------
// Get the valid descriptors that can be added under the targetEObject
Collection descriptors = null;
try {
descriptors = ModelerCore.getModelEditor().getNewChildCommands(targetEObject);
} catch (final ModelerCoreException e) {
final String message = getString("getOperationDescriptor.errMsg"); //$NON-NLS-1$
WebServicePlugin.Util.log(IStatus.ERROR, e, message);
return null;
}
// Use the first InterfaceAspect found
final Iterator iter = descriptors.iterator();
while (iter.hasNext()) {
operationDescriptor = (org.eclipse.emf.common.command.Command)iter.next();
final EObject eObj = (EObject)operationDescriptor.getResult().iterator().next();
// If the descriptor is a ColumnAspect, stop
final SqlAspect aspect = SqlAspectHelper.getSqlAspect(eObj);
if (aspect instanceof OperationAspect) break;
}
return operationDescriptor;
}
private static org.eclipse.emf.common.command.Command getOperationInputDescriptor( final EObject targetEObject ) {
org.eclipse.emf.common.command.Command operationInputDescriptor = null;
// ------------------------------------------------
// Get the Descriptor for OperationAspect
// ------------------------------------------------
// Get the valid descriptors that can be added under the targetEObject
Collection descriptors = null;
try {
descriptors = ModelerCore.getModelEditor().getNewChildCommands(targetEObject);
} catch (final ModelerCoreException e) {
final String message = getString("getOperationInputDescriptor.errMsg"); //$NON-NLS-1$
WebServicePlugin.Util.log(IStatus.ERROR, e, message);
return null;
}
// Use the first InterfaceAspect found
final Iterator iter = descriptors.iterator();
while (iter.hasNext()) {
operationInputDescriptor = (org.eclipse.emf.common.command.Command)iter.next();
final EObject eObj = (EObject)operationInputDescriptor.getResult().iterator().next();
// If the descriptor is a ColumnAspect, stop
final SqlAspect aspect = SqlAspectHelper.getSqlAspect(eObj);
if (aspect instanceof InputAspect) break;
}
return operationInputDescriptor;
}
private static org.eclipse.emf.common.command.Command getOperationOutputDescriptor( final EObject targetEObject ) {
org.eclipse.emf.common.command.Command operationOutputDescriptor = null;
// ------------------------------------------------
// Get the Descriptor for OperationAspect
// ------------------------------------------------
// Get the valid descriptors that can be added under the targetEObject
Collection descriptors = null;
try {
descriptors = ModelerCore.getModelEditor().getNewChildCommands(targetEObject);
} catch (final ModelerCoreException e) {
final String message = getString("getOperationOutputDescriptor.errMsg"); //$NON-NLS-1$
WebServicePlugin.Util.log(IStatus.ERROR, e, message);
return null;
}
// Use the first InterfaceAspect found
final Iterator iter = descriptors.iterator();
while (iter.hasNext()) {
operationOutputDescriptor = (org.eclipse.emf.common.command.Command)iter.next();
final EObject eObj = (EObject)operationOutputDescriptor.getResult().iterator().next();
// If the descriptor is a ColumnAspect, stop
final SqlAspect aspect = SqlAspectHelper.getSqlAspect(eObj);
if (aspect instanceof OutputAspect) break;
}
return operationOutputDescriptor;
}
/**
* Utility to get localized text.
*
* @param theKey the key whose value is being localized
* @return the localized text
*/
private static String getString( final String theKey ) {
return WebServicePlugin.Util.getString(new StringBuffer().append(PREFIX).append(theKey).toString());
}
/**
* Determine if the proposed model name is valid, and return an error message if it is not.
*
* @param proposedName
* @return null if the name is valid, or an error message if it is not.
*/
public static String validateModelName( String proposedName,
final String fileExtension ) {
boolean removedValidExtension = false;
if (proposedName.endsWith(fileExtension)) {
proposedName = proposedName.substring(0, proposedName.lastIndexOf(fileExtension));
removedValidExtension = true;
}
if (proposedName.indexOf('.') != -1) if (!removedValidExtension) return WebServicePlugin.Util.getString("ModelUtilities.illegalExtensionMessage", fileExtension); //$NON-NLS-1$
final ValidationResultImpl result = new ValidationResultImpl(proposedName);
CoreValidationRulesUtil.validateStringNameChars(result, proposedName, null);
if (result.hasProblems()) return result.getProblems()[0].getMessage();
return null;
}
private final PluginUtil Util = WebServicePlugin.Util;
private MultiStatus result;
private String parentPath;
private ModelResource wsModel;
private Collection transformationsToFinish;
private boolean createMultipleWebServices = false;
private boolean useLocationContainer;
private IContainer locationContainer;
private PostProcessor postProcessor;
/**
* Public constructor
*/
public WebServiceBuilderHelper() {
super();
this.result = new MultiStatus(WebServicePlugin.PLUGIN_ID, 0, Util.getString("WebServiceBuilderHelper.result"), null);//$NON-NLS-1$
}
private void addStatus( final String msg,
final int severity,
final Throwable err ) {
if (this.result == null) this.result = new MultiStatus(WebServicePlugin.PLUGIN_ID, 0,
Util.getString("WebServiceBuilderHelper.result"), null);//$NON-NLS-1$
final Status status = new Status(severity, WebServicePlugin.PLUGIN_ID, 0, msg, err);
result.add(status);
}
/**
* Method for creating a new WebService Model interface
*
* @param model - the model to create the interface in
* @param interfaceName - the name of the interface to create
* @return the created Interface may be NULL.
*/
private Object createInterface( final Resource resource,
final String interfaceName,
IProgressMonitor monitor ) {
EObject newInterface = null;
monitor = monitor == null ? new NullProgressMonitor() : monitor;
// first, see if this interface already exists
for (final Object element : resource.getContents()) {
final EObject obj = (EObject)element;
if (obj instanceof Interface) if (interfaceName.equals(((Interface)obj).getName())) return obj;
}
// Intialize Txn if required
final String txnDescr = getString("createInterface.txnDescr"); //$NON-NLS-1$
// Detmine TXN status and start one if required.
// This operation is not undoable OR significant.
final boolean startedTxn = ModelerCore.startTxn(false, false, txnDescr, WebServiceBuilderHelper.this);
try {
// Get the descriptor for a SqlColumn from the target
final org.eclipse.emf.common.command.Command interfaceToCreate = getInterfaceDescriptor(resource);
if (interfaceToCreate != null) // Create a new Interface with the specified name
try {
newInterface = ModelerCore.getModelEditor().createNewRootObjectFromCommand(resource, interfaceToCreate);
ModelerCore.getModelEditor().rename(newInterface, interfaceName);
} catch (final ModelerCoreException theException) {
final String message = getString("createInterface.errMsg"); //$NON-NLS-1$
WebServicePlugin.Util.log(IStatus.ERROR, theException, message);
}
} catch (final Exception e) {
final String message = getString("createInterface.errMsg"); //$NON-NLS-1$
addStatus(message, IStatus.ERROR, e);
} finally {
// This Txn is not undoable and not significant. Always commit.
if (startedTxn) ModelerCore.commitTxn();
}
return newInterface;
}
/**
* Method for creating a new WebService Model
*
* @param modelName - name of the model to create
* @param monitor - Progress Monitor
* @return the created Model may be NULL.
*/
private Object createModel( final ModelProject project,
final String modelName,
IProgressMonitor monitor ) {
Object newModel = null;
monitor = monitor == null ? new NullProgressMonitor() : monitor;
// Intialize Txn if required
final String txnDescr = getString("createModel.txnDescr"); //$NON-NLS-1$
// Detmine TXN status and start one if required.
// This operation is not undoable OR significant.
final boolean startedTxn = ModelerCore.startTxn(false, false, txnDescr, WebServiceBuilderHelper.this);
try {
boolean foundExisting = false;
// First see if we can find an existing model in the supplied project
// Get all of the webService models in the project
final List wsModels = getWebServiceModelsForProject(project);
final Iterator iter = wsModels.iterator();
while (iter.hasNext()) {
final Object mr = iter.next();
String mName = null;
if (mr instanceof ModelResource) mName = ModelerCore.getModelEditor().getModelName((ModelResource)mr);
else if (mr instanceof Resource) mName = ModelerCore.getModelEditor().getModelName((Resource)mr);
if (mName != null && mName.equalsIgnoreCase(modelName)) {
newModel = mr;
foundExisting = true;
break;
}
}
// If existing model not found, go ahead and create
if (!foundExisting) if (HEADLESS) newModel = this.createWebServiceModel(null, modelName);
else {
final IResource targetResource = project.getResource();
if (this.isValidWebServiceModelName(targetResource, modelName)) newModel = this.createWebServiceModel(targetResource,
modelName);
}
} catch (final Exception e) {
final String err = getString("createModel.errMsg"); //$NON-NLS-1$
addStatus(err, IStatus.ERROR, e);
} finally {
// This Txn is not undoable and not significant. Always commit.
if (startedTxn) ModelerCore.commitTxn();
}
return newModel;
}
/**
* Method for creating a new WebService Model interface
*
* @param model - the model to create the interface in
* @param interfaceName - the name of the interface to create
* @return the created Interface may be NULL.
*/
private Object createOperation( final EObject theInterface,
String operationName,
final String inputName,
final String outputName,
IProgressMonitor monitor ) {
EObject newOperation = null;
monitor = monitor == null ? new NullProgressMonitor() : monitor;
// dis-ambiguate the name as necessary
final Interface i = (Interface)theInterface;
final ArrayList opNames = new ArrayList(i.getOperations().size());
for (final Iterator iter = i.getOperations().iterator(); iter.hasNext();)
opNames.add(((Operation)iter.next()).getName());
String newName = operationName;
final Collection siblings = i.getOperations();
if (siblings != null) {
final Set siblingNames = new HashSet();
for (final Iterator it = siblings.iterator(); it.hasNext();)
siblingNames.add(((Operation)it.next()).getName());
boolean foundUniqueName = false;
int index = 1;
while (!foundUniqueName)
if (siblingNames.contains(newName)) newName = operationName + String.valueOf(index++);
else foundUniqueName = true;
}
operationName = newName;
// Intialize Txn if required
final String txnDescr = getString("createOperation.txnDescr"); //$NON-NLS-1$
// Detmine TXN status and start one if required.
// This operation is not undoable OR significant.
final boolean startedTxn = ModelerCore.startTxn(false, false, txnDescr, WebServiceBuilderHelper.this);
try {
// Get the descriptor for a SqlColumn from the target
final org.eclipse.emf.common.command.Command operationToCreate = getOperationDescriptor(theInterface);
if (operationToCreate != null) // Create a new Operation with the specified name
try {
newOperation = ModelerCore.getModelEditor().createNewChildFromCommand(theInterface, operationToCreate);
ModelerCore.getModelEditor().rename(newOperation, operationName);
if (inputName != null) {
final org.eclipse.emf.common.command.Command operationInputToCreate = getOperationInputDescriptor(newOperation);
final EObject newInputMessage = ModelerCore.getModelEditor().createNewChildFromCommand(newOperation,
operationInputToCreate);
ModelerCore.getModelEditor().rename(newInputMessage, inputName);
}
final org.eclipse.emf.common.command.Command operationOutputToCreate = getOperationOutputDescriptor(newOperation);
final EObject newOutputMessage = ModelerCore.getModelEditor().createNewChildFromCommand(newOperation,
operationOutputToCreate);
ModelerCore.getModelEditor().rename(newOutputMessage, outputName);
if (newOperation != null) NewModelObjectHelperManager.helpCreate(newOperation, null);
} catch (final ModelerCoreException theException) {
final String message = getString("createOperation.errMsg"); //$NON-NLS-1$
WebServicePlugin.Util.log(IStatus.ERROR, theException, message);
}
} catch (final Exception e) {
final String message = getString("createOperation.errMsg"); //$NON-NLS-1$
addStatus(message, IStatus.ERROR, e);
} finally {
// This Txn is not undoable and not significant. Always commit.
if (startedTxn) ModelerCore.commitTxn();
}
return newOperation;
}
/**
* Create a SQL assignment statement using the supplied info
*
* @param elem the supplied XSDElementDeclaration.
* @return the assignment statement
*/
private String createSqlAssignment( final Operation operation,
final XSDElementDeclaration elem ) {
final StringBuffer sbuffer = new StringBuffer();
if (operation != null && elem != null) {
final String operationInputName = getSqlFullName(operation.getInput());
final String name = elem.getName();
sbuffer.append(WebServiceUtil.INPUT_VARIABLE_PREFIX);
sbuffer.append(name.toUpperCase());
sbuffer.append(" = xPathValue("); //$NON-NLS-1$
sbuffer.append(operationInputName);
sbuffer.append(", '"); //$NON-NLS-1$
// Create XSD instance node tree and find element within it
final XsdInstanceNode node = findNode(new XsdInstanceNode(operation.getInput().getContentElement()), elem);
// Create XPath for element using its node
sbuffer.append(WebServiceUtil.createXPath(node));
sbuffer.append("');"); //$NON-NLS-1$
}
return sbuffer.toString();
}
/**
* Create a SQL assignment statement using the supplied info
*
* @param elem the supplied XSDElementDeclaration.
* @return the assignment statement
*/
private String createSqlCriteria( final XmlElement docElem,
final XSDElementDeclaration elem ) {
XmlElement docInstanceElem = docElem;
// Navigate one level down to get instance element
final List elementChildren = docElem.eContents();
final Iterator iter = elementChildren.iterator();
while (iter.hasNext()) {
final Object obj = iter.next();
if (obj instanceof XmlSequence) {
final XmlSequence seq = (XmlSequence)obj;
final List seqElems = seq.getEntities();
final Object seqElemObj = seqElems.get(0);
if (seqElemObj instanceof XmlElement) {
docInstanceElem = (XmlElement)seqElemObj;
break;
}
}
}
final StringBuffer sbuffer = new StringBuffer();
if (docInstanceElem != null && elem != null) {
final String docStr = getSqlFullName(docInstanceElem);
final String inpName = elem.getName();
if (docStr != null) {
final Container cntr = ModelerCore.getContainer(docElem);
final String runtimeType = cntr.getDatatypeManager().getRuntimeTypeName(elem.getType());
sbuffer.append(docStr);
sbuffer.append("."); //$NON-NLS-1$
sbuffer.append(inpName);
IDataTypeManagerService service = ModelerCore.getTeiidDataTypeManagerService();
if (runtimeType != null && !runtimeType.equals(service.getDefaultDataType(DataTypeName.STRING))) {
sbuffer.append(" = convert("); //$NON-NLS-1$
sbuffer.append(WebServiceUtil.INPUT_VARIABLE_PREFIX);
sbuffer.append(inpName.toUpperCase());
sbuffer.append(", ");//$NON-NLS-1$
sbuffer.append(runtimeType);
sbuffer.append(")");//$NON-NLS-1$
} else {
sbuffer.append(" = "); //$NON-NLS-1$
sbuffer.append(WebServiceUtil.INPUT_VARIABLE_PREFIX);
sbuffer.append(inpName.toUpperCase());
}
} else {
sbuffer.append("DocElement = "); //$NON-NLS-1$
sbuffer.append(WebServiceUtil.INPUT_VARIABLE_PREFIX);
sbuffer.append(inpName.toUpperCase());
}
}
return sbuffer.toString();
}
/**
* Create a SQL variable declaration statement using the supplied XSDElementDeclaration
*
* @param elem the supplied XSDElementDeclaration.
* @return the variable declaration statement
*/
private String createSqlDeclaration( final XSDElementDeclaration elem ) {
final StringBuffer sbuffer = new StringBuffer();
if (elem != null) {
sbuffer.append("DECLARE string " + WebServiceUtil.INPUT_VARIABLE_PREFIX); //$NON-NLS-1$
sbuffer.append(elem.getName().toUpperCase());
sbuffer.append(";"); //$NON-NLS-1$
}
return sbuffer.toString();
}
/**
* generate a Webservice model / interface from the supplied buildOptions
*
* @param buildOptions the builder options
* @param autoGenSQL flag indicating that the buildOptions are being passed from the end-to-end wizard - there for we can
* auto-generate the SQL using the input and output message elements.
* @param saveModel flag indicating whether to save the Model. If this method is being called multiple times, the flag is set to
* false - since save will kick of workspace build and collide with indexing.
* @param monitor the progress monitor
* @return result MultiStatus
*/
public MultiStatus createWebService( final WebServiceBuildOptions buildOptions,
final boolean autoGenSQL,
final boolean saveModel,
final IProgressMonitor monitor ) {
this.useLocationContainer = buildOptions.shouldUseLocationContainer();
this.locationContainer = buildOptions.getLocationContainer();
// Intialize Txn if required
final String txnDescr = getString("createWebService.txnDescr"); //$NON-NLS-1$
// Detmine TXN status and start one if required.
final boolean startedTxn = ModelerCore.startTxn(false, false, txnDescr, WebServiceBuilderHelper.this);
try {
// -------------------------------------------
// Get the project to create model within
// -------------------------------------------
final ModelProject project = buildOptions.getCurrentProject();
ModelResource model = null;
Resource resource = null;
// -------------------------------------------------
// Create model or use existing model if selected
// -------------------------------------------------
// Determine if a new model needs to be create
final Object modelObj = buildOptions.getModel();
if (modelObj != null && modelObj instanceof ModelResource) {
model = (ModelResource)modelObj;
resource = model.getEmfResource();
} else if (modelObj instanceof String) {
final String modelName = (String)modelObj;
final Object returnedObj = createModel(project, modelName, monitor);
if (returnedObj instanceof ModelResource) {
model = (ModelResource)returnedObj;
wsModel = model;
resource = model.getEmfResource();
} else if (HEADLESS && returnedObj instanceof Resource) resource = (Resource)returnedObj;
}
postProcessor = new PostProcessor(model);
// ---------------------------------------------------------
// Create interface or use existing interface if selected
// ---------------------------------------------------------
Interface theInterface = null;
// Now create the interface if necessary
if (resource != null && result.getSeverity() < IStatus.ERROR) {
final Object interfaceObj = buildOptions.getInterface();
if (interfaceObj != null && interfaceObj instanceof Interface) theInterface = (Interface)interfaceObj;
else if (interfaceObj instanceof String) {
final String interfaceName = (String)interfaceObj;
final Object returnedObj = createInterface(resource, interfaceName, monitor);
if (returnedObj instanceof Interface) theInterface = (Interface)returnedObj;
}
}
// ---------------------------------------------------------
// Create operation
// ---------------------------------------------------------
Operation theOperation = null;
// Now create the operation if necessary
if (theInterface != null && result.getSeverity() < IStatus.ERROR) {
final String operationName = buildOptions.getOperationName();
final String operationInputMessageName = buildOptions.getOperationInputMessageName();
final String operationOutputMessageName = buildOptions.getOperationOutputMessageName();
final Object returnedObj = createOperation(theInterface,
operationName,
operationInputMessageName,
operationOutputMessageName,
monitor);
if (returnedObj instanceof Operation) theOperation = (Operation)returnedObj;
}
// ---------------------------------------------------------
// Set the operation messages and properties
// ---------------------------------------------------------
XmlDocument outputDoc = null;
if (theOperation != null && result.getSeverity() < IStatus.ERROR) {
final XSDElementDeclaration inputElem = buildOptions.getOperationInputMessageElem();
final XSDElementDeclaration outputElem = buildOptions.getOperationOutputMessageElem();
outputDoc = buildOptions.getOperationOutputXmlDoc();
final Input opInput = theOperation.getInput();
if (opInput != null) opInput.setContentElement(inputElem);
final Output opOutput = theOperation.getOutput();
if (opOutput != null) {
opOutput.setContentElement(outputElem);
opOutput.setXmlDocument(outputDoc);
}
}
// ---------------------------------------------------------
// Force indexing of model - fixes problem where not all
// of the result queries were validating...
// ---------------------------------------------------------
if (!HEADLESS) {
// ---------------------------------------------------------
// Generate SQL and set it on the mappingRoot
// ---------------------------------------------------------
final TransformationFinisher finisher = new TransformationFinisher(model, outputDoc, theOperation, autoGenSQL);
if (!createMultipleWebServices) finisher.finish();
else transformationsToFinish.add(finisher);
}
try {
if(model!=null) ModelBuildUtil.rebuildImports(model.getEmfResource(), false);
//Rebuild project
model.getResource().getProject().build(IncrementalProjectBuilder.CLEAN_BUILD, null);
} catch (final ModelWorkspaceException e) {
Util.log(e);
}
// ---------------------------------------------------------
// Save Model
// ---------------------------------------------------------
if (saveModel)
try {
model.save(monitor, true);
} catch (final Exception e) {
final String saveError = getString("createWebService.errSave"); //$NON-NLS-1$
addStatus(saveError, IStatus.ERROR, e);
}
} catch (final Exception e) {
final String err = getString("createWebService.errMsg"); //$NON-NLS-1$
addStatus(err, IStatus.ERROR, e);
} finally {
// This Txn is not undoable and not significant. Always commit.
if (startedTxn) ModelerCore.commitTxn();
}
return result;
}
/**
* Create a Relationships Model with the supplied name, in the desired project
*
* @param targetProj the project resource under which to create the model
* @param modelName the model name to create
* @return the newly-created ModelResource
*/
private Object createWebServiceModel( final IResource targetRes,
final String modelName ) {
String fileName = getFileName(modelName);
if (HEADLESS) {
if (parentPath != null) fileName = parentPath + File.separator + modelName;
final URI uri = URI.createURI(fileName);
try {
final Resource rsrc = ModelerCore.getModelContainer().createResource(uri);
final ModelContents mc = ModelerCore.getModelEditor().getModelContents(rsrc);
mc.getModelAnnotation().setPrimaryMetamodelUri(WebServicePackage.eNS_URI);
mc.getModelAnnotation().setModelType(ModelType.VIRTUAL_LITERAL);
return rsrc;
} catch (final CoreException err) {
// Do nothing, return null;
return null;
}
}
IFile modelFile = null;
ModelResource resrc = null;
boolean exists = false;
if (parentPath == null) {
IPath relativeModelPath = null;
if (useLocationContainer) {
final IWorkspaceRoot wsroot = ModelerCore.getWorkspace().getRoot();
relativeModelPath = this.locationContainer.getFullPath();
modelFile = wsroot.getFileForLocation(wsroot.getRawLocation().append(relativeModelPath).append(fileName));
} else {
relativeModelPath = targetRes.getProjectRelativePath().append(fileName);
modelFile = targetRes.getProject().getFile(relativeModelPath);
}
} else {
// case 4133: Add logic to create new WS model at a given parent path rather than always
// as a root model.
final IPath path = new Path(parentPath + File.separator + fileName);
final IWorkspaceRoot wsroot = ModelerCore.getWorkspace().getRoot();
modelFile = wsroot.getFileForLocation(path);
exists = new File(path.toString()).exists();
}
if (modelFile != null) {
resrc = ModelerCore.create(modelFile);
if (!exists) // Found this working 4133... don't always reset the attributes. If the model
// already exists, no need to reset these attributes
try {
resrc.getModelAnnotation().setPrimaryMetamodelUri(WebServicePackage.eNS_URI);
resrc.getModelAnnotation().setModelType(ModelType.VIRTUAL_LITERAL);
try {
final String msg = Util.getString("WebServiceBuilderHelper.newModel", modelFile.getName()); //$NON-NLS-1$
addStatus(msg, IStatus.INFO, null);
resrc.save(null, false);
} catch (final ModelWorkspaceException e) {
WebServicePlugin.Util.log(e);
}
} catch (final ModelWorkspaceException e) {
e.printStackTrace();
}
}
return resrc;
}
/**
* generate Webservices from the supplied buildOptions collection
*
* @param buildOptions a collection of WebServiceBuildOption objects
* @param autoGenSQL flag indicating that the buildOptions are being passed from the end-to-end wizard - there for we can
* auto-generate the SQL using the input and output message elements.
* @param monitor the progress monitor
* @return messages string buffer
*/
public MultiStatus createWebServices( final Collection buildOptions,
final boolean autoGenSQL,
final MultiStatus result,
final IProgressMonitor monitor ) {
// Intialize Txn if required
if (result != null) this.result = result;
createMultipleWebServices = true;
final String txnDescr = getString("createWebServices.txnDescr"); //$NON-NLS-1$
// Detmine TXN status and start one if required.
final boolean startedTxn = ModelerCore.startTxn(false, false, txnDescr, WebServiceBuilderHelper.this);
try {
if (buildOptions != null && buildOptions.size() > 0) {
transformationsToFinish = new ArrayList(buildOptions.size());
final Iterator iter = buildOptions.iterator();
while (iter.hasNext()) {
final WebServiceBuildOptions option = (WebServiceBuildOptions)iter.next();
createWebService(option, autoGenSQL, false, monitor);
}
// Find models to index
final Collection modelsToIndex = new HashSet();
for (final Iterator iter2 = transformationsToFinish.iterator(); iter2.hasNext();) {
final TransformationFinisher finisher = (TransformationFinisher)iter2.next();
modelsToIndex.add(finisher.model);
}
if (!modelsToIndex.isEmpty()) {
final Collection iResources = new HashSet(modelsToIndex.size());
for (final Iterator iter2 = modelsToIndex.iterator(); iter2.hasNext();) {
final ModelResource mr = (ModelResource)iter2.next();
final IResource resrc = mr.getCorrespondingResource();
if (resrc != null) iResources.add(resrc);
}
ModelBuildUtil.indexResources(null, iResources);
}
// Now we finish the transformations
for (final Iterator iter2 = transformationsToFinish.iterator(); iter2.hasNext();) {
final TransformationFinisher finisher = (TransformationFinisher)iter2.next();
finisher.finish();
}
saveModels(buildOptions, monitor);
}
} catch (final Exception e) {
final String err = getString("createWebServices.errMsg"); //$NON-NLS-1$
addStatus(err, IStatus.ERROR, e);
} finally {
// This Txn is not undoable and not significant. Always commit.
if (startedTxn) ModelerCore.commitTxn();
}
createMultipleWebServices = false;
return result;
}
/**
* Create a WHERE clause using the supplied list of criteria
*
* @param sqlCriteria the supplied list of criteria
* @return the WHERE statement string
*/
private String createWhereClause( final List sqlCriteria ) {
final StringBuffer sbuffer = new StringBuffer();
if (sqlCriteria != null && !sqlCriteria.isEmpty()) {
sbuffer.append(" WHERE "); //$NON-NLS-1$
final Iterator criteriaIter = sqlCriteria.iterator();
while (criteriaIter.hasNext()) {
sbuffer.append(" ("); //$NON-NLS-1$
sbuffer.append((String)criteriaIter.next());
sbuffer.append(") "); //$NON-NLS-1$
if (criteriaIter.hasNext()) sbuffer.append(" AND "); //$NON-NLS-1$
}
}
return sbuffer.toString();
}
private XsdInstanceNode findNode( XsdInstanceNode node,
final XSDElementDeclaration element ) {
if (node.getResolvedXsdComponent() == element) return node;
final XsdInstanceNode[] nodes = node.getChildren();
for (int ndx = nodes.length; --ndx >= 0;) {
node = findNode(nodes[ndx], element);
if (node != null) return node;
} // for
return null;
}
/**
* generate default sql procedure. This SQL is strictly a starting point that the user can edit as desired. It contains an
* example variable declaration and assignment. It is up to the user to add the sql criteria.
*
* @param outputDoc the xml output document
* @param operation the webservice operation, used to get the input message
* @return the default SQL String
*/
String generateDefaultSQL( final XmlDocument outputDoc,
final Operation operation ) {
final StringBuffer sbuffer = new StringBuffer();
// Start the procedure
sbuffer.append("CREATE VIRTUAL PROCEDURE "); //$NON-NLS-1$
sbuffer.append("BEGIN "); //$NON-NLS-1$
// Create the default SELECT * FROM query using the output document
final IQuery qry = TransformationSqlHelper.createDefaultQuery(outputDoc);
if (qry != null) {
sbuffer.append(qry.toString());
sbuffer.append(";"); //$NON-NLS-1$
}
// End the procedure
sbuffer.append(" END"); //$NON-NLS-1$
return sbuffer.toString();
}
/**
* generate SQL using the input and output message elements from the operation. This method can be used on operations generated
* by the WebService Generation Wizard only. There are assumptions made about the input element type, etc. Very difficult to
* handle generically.
*
* @param outputDoc the xml output document
* @param operation the webservice operation, used to get the input message
* @return the default SQL String
*/
String generateSQLUsingMessageElements( final XmlDocument outputDoc,
final Operation operation ) {
if (HEADLESS)
return generateDefaultSQL(outputDoc, operation);
final StringBuffer sbuffer = new StringBuffer();
// Start the procedure
sbuffer.append("CREATE VIRTUAL PROCEDURE "); //$NON-NLS-1$
sbuffer.append("BEGIN "); //$NON-NLS-1$
// Create Declarations if elements are available
List<String> declarationList = new ArrayList<String>();
// Create Declaration Assignments if elements are available
List<String> assignmentList = new ArrayList<String>();
// Create Criteria if elements are available
List<String> criteriaList = new ArrayList<String>();
// Add variable declarations based on operation input elements
List inputElems = WebServiceUtil.getInputElements(operation, true);
Iterator inpIter = inputElems.iterator();
if (!inputElems.isEmpty()) {
// Find the document element matching the operation output message element
XmlElement docElement = getDocElemMatchingOperationOutputElem(outputDoc, operation);
while (inpIter.hasNext()) {
// Declarations
XSDElementDeclaration declaration = (XSDElementDeclaration) inpIter.next();
final String sqlDeclare = createSqlDeclaration(declaration);
declarationList.add(sqlDeclare);
// Variable Assignments
final String sqlAssign = createSqlAssignment(operation, declaration);
assignmentList.add(sqlAssign);
// Create the individual criteria
final String criteria = createSqlCriteria(docElement, declaration);
criteriaList.add(criteria);
}
}
for (String sqlDeclare : declarationList) {
sbuffer.append(sqlDeclare);
}
// Add the variable assignments
// InputElements supplied - build the assignments from them.
for (String sqlAssign : assignmentList) {
sbuffer.append(sqlAssign);
}
// Create the default SELECT * FROM query using the output document
final IQuery qry = TransformationSqlHelper.createDefaultQuery(outputDoc);
// Add query to the procedure
if (qry != null) {
// append default query
sbuffer.append(qry.toString());
// If criteria were created, create the compound where and add it to the query
if (!criteriaList.isEmpty()) {
final String whereClause = createWhereClause(criteriaList);
sbuffer.append(whereClause);
}
// End the query statement
sbuffer.append(";"); //$NON-NLS-1$
}
// End the procedure
sbuffer.append(" END"); //$NON-NLS-1$
return sbuffer.toString();
}
/**
* This method will get the XmlElement from the supplied XmlDocument, which has the supplied XsdComponent property.
*
* @param xmlDoc - the XmlDocument to search
* @param operation - the webservice operation
* @return the xmlDocument element whose xsdComponent matches the operation output.
*/
private XmlElement getDocElemMatchingOperationOutputElem( final XmlDocument xmlDoc,
final Operation operation ) {
XmlElement docElement = null;
if (xmlDoc != null && operation != null) {
final Output outp = operation.getOutput();
final XSDElementDeclaration outputElem = outp.getContentElement();
final Iterator docIter = xmlDoc.eAllContents();
while (docIter.hasNext()) {
final Object elem = docIter.next();
if (elem instanceof XmlElement) {
final XmlElement xmlElem = (XmlElement)elem;
final XSDComponent xsdComp = xmlElem.getXsdComponent();
if (xsdComp != null && xsdComp.equals(outputElem)) {
docElement = xmlElem;
break;
}
}
}
}
return docElement;
}
/**
* get the full file name, given a modelName string
*
* @param modelName the model name
* @return the full model name, including extension
*/
private String getFileName( final String modelName ) {
String result = modelName.trim();
if (!result.endsWith(FILE_EXT)) result += FILE_EXT;
return result;
}
/**
* @return Returns the parentPath.
* @since 4.3
*/
public String getParentPath() {
return this.parentPath;
}
/**
* Get the Sql FullName for the supplied EObject
*
* @param eObj the supplied EObject.
* @return the full name of the EObject.
*/
private String getSqlFullName( final EObject eObj ) {
String fullName = null;
if (eObj != null) {
// Get the full name from Sql aspect
final SqlAspect aspect = SqlAspectHelper.getSqlAspect(eObj);
if (aspect != null) fullName = aspect.getFullName(eObj);
}
return fullName;
}
public ModelResource getWebServiceModel() {
return this.wsModel;
}
/**
* Get the List of WebService Models for the provided project
*
* @param project the model project
* @return the List of WebService Models in the project
*/
private List getWebServiceModelsForProject( final ModelProject project ) {
if (HEADLESS) {
final List result = new ArrayList();
try {
final Iterator resources = ModelerCore.getModelContainer().getResources().iterator();
while (resources.hasNext()) {
final Resource next = (Resource)resources.next();
if (next instanceof MtkXmiResourceImpl) {
final ModelContents contents = ModelerCore.getModelEditor().getModelContents(next);
final ModelAnnotation ma = contents.getModelAnnotation();
if (WebServicePackage.eNS_URI.equals(ma.getPrimaryMetamodelUri())) result.add(next);
}
}
} catch (final Exception err) {
// Do nothing, just return the result
}
return result;
}
final List allWebServiceModels = new ArrayList();
ModelWorkspaceItem[] workspaceItems = null;
try {
workspaceItems = project.getChildren();
} catch (final ModelWorkspaceException err) {
}
if (workspaceItems != null) for (final ModelWorkspaceItem workspaceItem : workspaceItems) {
IResource resource = null;
try {
resource = workspaceItem.getCorrespondingResource();
} catch (final ModelWorkspaceException err) {
}
ModelResource mr = null;
if (resource instanceof IFile) {
try {
mr = ModelerCore.getModelEditor().findModelResource(resource);
} catch (final ModelWorkspaceException e) {
e.printStackTrace();
}
if (mr != null && WebServiceUtil.isWebServiceModelResource(mr)) allWebServiceModels.add(mr);
}
}
return allWebServiceModels;
}
/**
* test whether the supplied modelName is valid
*
* @param modelName the model name to test
* @return 'true' if the name is valid, 'false' if not.
*/
private boolean isValidWebServiceModelName( final IResource targetResource,
final String modelName ) {
// Check for null or zero-length
if (modelName == null || modelName.length() == 0) return false;
// Check for valid model name
final String fileNameMessage = validateModelName(modelName, FILE_EXT);
if (fileNameMessage != null) return false;
// Check if already exists
final String fileName = getFileName(modelName);
IPath modelRelativePath = null;
if (targetResource != null) modelRelativePath = targetResource.getProjectRelativePath().append(fileName);
if (targetResource != null && targetResource.getProject().exists(modelRelativePath)) return false;
// success
return true;
}
/**
* save the models specified in the options list.
*
* @param webServiceBuildOptions the list of webService build options
* @param monitor - Progress Monitor
*/
private void saveModels( final Collection webServiceBuildOptions,
IProgressMonitor monitor ) {
monitor = monitor == null ? new NullProgressMonitor() : monitor;
// Intialize Txn if required
final String txnDescr = getString("saveModels.txnDescr"); //$NON-NLS-1$
// Detmine TXN status and start one if required.
// This operation is not undoable OR significant.
final boolean startedTxn = ModelerCore.startTxn(false, false, txnDescr, WebServiceBuilderHelper.this);
// keep track of already saved models - no need to save them twice.
final List savedModels = new ArrayList();
try {
final Iterator wsOptionsIter = webServiceBuildOptions.iterator();
while (wsOptionsIter.hasNext()) {
final WebServiceBuildOptions wsOption = (WebServiceBuildOptions)wsOptionsIter.next();
final Object model = wsOption.getModel();
// Supplied Model is a ModelResource
if (model instanceof ModelResource) {
final ModelResource modelRes = (ModelResource)model;
if (!savedModels.contains(modelRes)) {
modelRes.save(monitor, true);
savedModels.add(modelRes);
}
// Supplied Model is a name String
} else if (model instanceof String) {
final String modelName = (String)model;
final ModelProject project = wsOption.getCurrentProject();
// Lookup model with the supplied same and save it if found
final List wsModels = getWebServiceModelsForProject(project);
final Iterator iter = wsModels.iterator();
while (iter.hasNext()) {
final Object tmp = iter.next();
String mName = null;
ModelResource mr = null;
if (tmp instanceof ModelResource) {
mr = (ModelResource)tmp;
mName = ModelerCore.getModelEditor().getModelName(mr);
} else if (tmp instanceof Resource) mName = ModelerCore.getModelEditor().getModelName((Resource)tmp);
if (mName != null && mName.equalsIgnoreCase(modelName) && mr != null) {
if (!savedModels.contains(mr)) {
mr.save(monitor, true);
savedModels.add(mr);
}
break;
}
}
}
}
} catch (final Exception e) {
final String err = getString("saveModels.errMsg"); //$NON-NLS-1$
addStatus(err, IStatus.ERROR, e);
} finally {
// This Txn is not undoable and not significant. Always commit.
if (startedTxn) ModelerCore.commitTxn();
}
}
/**
* @param parentPath The parentPath to set.
* @since 4.3
*/
public void setParentPath( final String parentPath ) {
this.parentPath = parentPath;
}
public void postProcess() {
if( postProcessor != null ) {
postProcessor.execute();
}
}
// /////////////////////////////////////////////////////////////////////////////////////////////
// TransformationFinisher INNER CLASS
// Provides means to delay setting sql text strings until after all WS models are completed
// This way, indexing can be done on the complete model first, then query resolution can be
// accomplished without error.
// /////////////////////////////////////////////////////////////////////////////////////////////
private class TransformationFinisher {
ModelResource model;
boolean autoGenSql;
XmlDocument xmlOutputDoc;
Operation operation;
public TransformationFinisher( final ModelResource theModel,
final XmlDocument theXmlDoc,
final Operation theOperation,
final boolean theAutoGenSql ) {
super();
model = theModel;
xmlOutputDoc = theXmlDoc;
operation = theOperation;
autoGenSql = theAutoGenSql;
}
protected void finish() {
// ---------------------------------------------------------
// Generate SQL and set it on the mappingRoot
// ---------------------------------------------------------
String sqlString = null;
if (autoGenSql) sqlString = generateSQLUsingMessageElements(xmlOutputDoc, operation);
else sqlString = generateDefaultSQL(xmlOutputDoc, operation);
// Set the SQL on the mapping root for the operation
final EObject mappingRoot = TransformationHelper.getMappingRoot(operation);
TransformationHelper.setSelectSqlString(mappingRoot, sqlString, false, null);
// reconcile mappings
TransformationMappingHelper.reconcileMappingsOnSqlChange(mappingRoot, null);
postProcessor.addRoot(operation, mappingRoot);
}
}
private class PostProcessor {
ModelResource wsModel;
Map<EObject, EObject> operationsMappingRoots;
public PostProcessor( final ModelResource wsModel) {
super();
this.wsModel = wsModel;
operationsMappingRoots = new HashMap<EObject, EObject>();
}
protected void addRoot(EObject operation, EObject root) {
operationsMappingRoots.put(operation, root);
}
public void execute() {
if( wsModel == null || operationsMappingRoots.isEmpty() ) {
return;
}
// This operation is not undoable OR significant.
final boolean startedTxn = ModelerCore.startTxn(false, false, "Reconciling Operations", WebServiceBuilderHelper.this); //$NON-NLS-1$
try {
// Need to invalidate the cache because it's currently "invalid" and needs to start from scratch
for( EObject nextOperation: operationsMappingRoots.keySet() ) {
SqlMappingRootCache.invalidateStatus(operationsMappingRoots.get(nextOperation), false, this);
}
for( EObject nextOperation: operationsMappingRoots.keySet() ) {
TransformationMappingHelper.reconcileTargetAttributes(operationsMappingRoots.get(nextOperation), null);
}
wsModel.save(new NullProgressMonitor(), true);
wsModel.getEmfResource().setModified(false);
} catch (final Exception e) {
WebServicePlugin.Util.log(IStatus.ERROR, e.getMessage());
} finally {
// This Txn is not undoable and not significant. Always commit.
if (startedTxn) ModelerCore.commitTxn();
}
}
}
}