/*
* 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;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xsd.XSDAnnotation;
import org.eclipse.xsd.XSDDiagnostic;
import org.eclipse.xsd.XSDDiagnosticSeverity;
import org.eclipse.xsd.XSDSchema;
import org.eclipse.xsd.XSDSchemaContent;
import org.eclipse.xsd.XSDSchemaDirective;
import org.eclipse.xsd.impl.XSDFactoryImpl;
import org.eclipse.xsd.impl.XSDImportImpl;
import org.eclipse.xsd.impl.XSDSchemaImpl;
import org.eclipse.xsd.util.XSDConstants;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.core.designer.util.ResourceNameUtil;
import org.teiid.designer.compare.ModelGenerator;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.metamodel.MetamodelDescriptor;
import org.teiid.designer.core.workspace.ModelWorkspaceItem;
import org.teiid.designer.core.workspace.ModelWorkspaceManager;
import org.teiid.designer.metamodels.wsdl.Definitions;
import org.teiid.designer.metamodels.wsdl.Import;
import org.teiid.designer.metamodels.wsdl.Types;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
/**
* Basic implementation of {@link org.teiid.designer.webservice.IWebServiceModelBuilder}. This class provides management of
* the various inputs to the Web Service builder, and can create the {@link ModelGenerator} that is used to execute the builder.
*
* @since 8.0
*/
public class BasicWebServiceModelBuilder implements IWebServiceModelBuilder {
private IResource parentResource;
private MetamodelDescriptor modelDescriptor;
private IPath modelPath;
private IPath xmlModel;
private final List resources;
private Collection selectedWsdlOperations;
private final Map emfResourceUriByWebServiceResource;
private final WebServiceResources resourceSet;
private List xsdWorkspaceResources;
private final Object xsdWorkspaceResourcesLock = new Object();
private boolean saveAllBeforeFinish = false;
private Map urlMap = new HashMap();
private boolean processedXsdResources = false;
public BasicWebServiceModelBuilder() {
this.resources = new ArrayList();
this.resourceSet = new WebServiceResources();
this.emfResourceUriByWebServiceResource = new HashMap();
this.selectedWsdlOperations = new HashSet();
this.xsdWorkspaceResources = new ArrayList();
this.processedXsdResources = false;
}
// =========================================================================
// Methods for the Web Service Model
// =========================================================================
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#getXmlModel()
* @since 4.2
*/
@Override
public IPath getXmlModel() {
return this.xmlModel;
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#getParentResource()
* @since 4.2
*/
@Override
public IResource getParentResource() {
return this.parentResource;
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#getModelPath()
* @since 4.2
*/
@Override
public IPath getModelPath() {
return this.modelPath;
}
@Override
public Map getUrlMap() {
return this.urlMap;
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#setMetamodelDescriptor(org.teiid.designer.core.metamodel.MetamodelDescriptor)
* @since 4.2
*/
@Override
public void setMetamodelDescriptor( MetamodelDescriptor theDescriptor ) {
this.modelDescriptor = theDescriptor;
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#setParentResource(org.eclipse.core.resources.IResource)
* @since 4.2
*/
@Override
public void setParentResource( IResource theResource ) {
this.parentResource = theResource;
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#setModelPath(org.eclipse.core.runtime.IPath)
* @since 4.2
*/
@Override
public void setModelPath( IPath thePath ) {
this.modelPath = thePath;
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#setXmlModel(org.eclipse.core.runtime.IPath)
* @since 4.2
*/
@Override
public void setXmlModel( IPath theXmlModel ) {
this.xmlModel = theXmlModel;
}
// =========================================================================
// Methods for the Input Files (WSDL and XSD)
// =========================================================================
protected IWebServiceResource addOrFind( final IWebServiceResource resource ) {
final Iterator iter = this.resources.iterator();
while (iter.hasNext()) {
final IWebServiceResource r = (IWebServiceResource)iter.next();
if (r.equals(resource)) {
return r;
}
}
// not found, so add
this.resources.add(resource);
return resource;
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#addResource(java.io.File)
* @since 4.2
*/
@Override
public IWebServiceResource addResource( File theFile ) throws CoreException {
CoreArgCheck.isNotNull(theFile);
// Check whether the file exists ...
if (!theFile.exists()) {
final Object[] params = new Object[] {theFile};
final String msg = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.FileDoesNotExist", params); //$NON-NLS-1$
throw new IllegalArgumentException(msg);
}
// Construct the URI and load the file ...
final URI uri = URI.createFileURI(theFile.getAbsolutePath());
Resource resource = null;
// if there is a problem adding/loading resource throw exception
try {
resource = this.resourceSet.add(uri);
} catch (Exception theException) {
this.resourceSet.remove(uri);
final String msg = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.ProblemLoadingWsdl", theFile); //$NON-NLS-1$
final Status status = new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, IStatus.OK, msg, theException);
throw new CoreException(status);
}
// Get the target namespace and construct a web service resource ...
final String targetNamespace = this.resourceSet.getTargetNamespace(resource);
AbstractWebServiceResource wsResource = new FileSystemWebServiceResource(targetNamespace, theFile);
this.emfResourceUriByWebServiceResource.put(wsResource.getFullPath(), uri);
// Add to the collection(s) ...
wsResource = (AbstractWebServiceResource)addOrFind(wsResource);
processedXsdResources = false;
xsdWorkspaceResources = new ArrayList();
return wsResource;
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#addResource(org.eclipse.core.resources.IFile)
* @since 4.2
*/
@Override
public IWebServiceResource addResource( IFile theFile ) throws CoreException {
CoreArgCheck.isNotNull(theFile);
// Check whether the file exists ...
if (!theFile.exists()) {
final Object[] params = new Object[] {theFile};
final String msg = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.FileDoesNotExist", params); //$NON-NLS-1$
throw new IllegalArgumentException(msg);
}
// Construct the URI and load the file ...
final URI uri = URI.createFileURI(theFile.getFullPath().toString());
Resource resource = null;
// if there is a problem adding/loading resource throw exception
try {
resource = this.resourceSet.add(uri);
} catch (Exception theException) {
this.resourceSet.remove(uri);
final String msg = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.ProblemLoadingWsdl", theFile); //$NON-NLS-1$
final Status status = new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, IStatus.OK, msg, theException);
throw new CoreException(status);
}
// Get the target namespace and construct a web service resource ...
final String targetNamespace = this.resourceSet.getTargetNamespace(resource);
AbstractWebServiceResource wsResource = new WorkspaceFileWebServiceResource(targetNamespace, theFile);
this.emfResourceUriByWebServiceResource.put(wsResource.getFullPath(), uri);
// Add to the collection(s) ...
wsResource = (AbstractWebServiceResource)addOrFind(wsResource);
processedXsdResources = false;
xsdWorkspaceResources = new ArrayList();
return wsResource;
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#resolve(org.teiid.designer.webservice.IWebServiceResource,
* java.io.File)
* @since 4.2
*/
@Override
public void resolve( IWebServiceResource resource,
File theFile ) {
CoreArgCheck.isNotNull(resource);
CoreArgCheck.isNotNull(theFile);
// Create the new web service resource ...
final IWebServiceResource resolved = new FileSystemWebServiceResource(resource.getNamespace(), theFile);
// Find the original resolved ...
final IWebServiceResource origResolvedResource = resolved.getResolvedResource();
// Set the input resource as resolved ...
if (resource instanceof AbstractWebServiceResource) {
((AbstractWebServiceResource)resource).setResolvedResource(resolved);
}
// Remove the original resolved ...
if (origResolvedResource != null) {
final Collection resolvesResources = origResolvedResource.getResourcesResolved();
if (resolvesResources.size() == 0) {
this.remove(origResolvedResource);
}
}
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#unresolve(org.teiid.designer.webservice.IWebServiceResource)
* @since 4.2
*/
@Override
public void unresolve( IWebServiceResource resource ) {
CoreArgCheck.isNotNull(resource);
if (resource.isResolved()) {
resource.setResolvedResource(null);
}
final URI uri = (URI)this.emfResourceUriByWebServiceResource.remove(resource.getFullPath());
if (uri != null) {
this.resourceSet.remove(uri);
}
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#resolve(org.teiid.designer.webservice.IWebServiceResource,
* org.eclipse.core.resources.IFile)
* @since 4.2
*/
@Override
public void resolve( IWebServiceResource resource,
IFile theFile ) {
CoreArgCheck.isNotNull(resource);
CoreArgCheck.isNotNull(theFile);
// Create the new web service resource ...
final IWebServiceResource resolved = new WorkspaceFileWebServiceResource(resource.getNamespace(), theFile);
// Find the original resolved ...
final IWebServiceResource origResolvedResource = resolved.getResolvedResource();
// Set the input resource as resolved ...
if (resource instanceof AbstractWebServiceResource) {
((AbstractWebServiceResource)resource).setResolvedResource(resolved);
}
// Remove the original resolved ...
if (origResolvedResource != null) {
final Collection resolvesResources = origResolvedResource.getResourcesResolved();
if (resolvesResources.size() == 0) {
this.remove(origResolvedResource);
}
}
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#remove(org.teiid.designer.webservice.IWebServiceResource)
* @since 4.2
*/
@Override
public void remove( IWebServiceResource theResource ) {
CoreArgCheck.isNotNull(theResource);
// Remove this resource ...
if (!this.resources.remove(theResource)) {
return;
}
// Unload the EMF resource (if already loaded) ...
final URI uri = (URI)this.emfResourceUriByWebServiceResource.remove(theResource.getFullPath());
if (uri != null) {
this.resourceSet.remove(uri);
}
// And remove anything else that can be ...
// Remove from the referencing resources ...
if (theResource instanceof AbstractWebServiceResource) {
final AbstractWebServiceResource wsResource = (AbstractWebServiceResource)theResource;
wsResource.removeFromAllReferencers();
// Remove the referenced resources ...
final Iterator iter = wsResource.getReferencedResources().iterator();
while (iter.hasNext()) {
final AbstractWebServiceResource referenced = (AbstractWebServiceResource)iter.next();
wsResource.removeReferencedResource(referenced);
// If reference isn't referenced by anybody else, clean it up ...
if (referenced.getReferencingResources().size() == 0) {
remove(referenced);
}
}
}
processedXsdResources = false;
xsdWorkspaceResources = new ArrayList();
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#getResources()
* @since 4.2
*/
@Override
public Collection getResources() {
return resources; // return is non-null
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#getEmfResource(org.teiid.designer.webservice.IWebServiceResource)
* @since 4.2
*/
@Override
public Resource getEmfResource( IWebServiceResource theResource ) {
final URI uri = (URI)this.emfResourceUriByWebServiceResource.get(theResource.getFullPath());
if (uri != null) {
return this.resourceSet.get(uri);
}
return null;
}
// =========================================================================
// Adding WSDL Resources to builder
// =========================================================================
/**
* This method will take any WSDL resources added to the resource list and will interrogate them for imports that reference
* other wSDL documents. If some are found they are added to the resource list and all internal collections. After all are
* found recursively, the complete set will be returned in the Collection returned from this method.
*
* @return a Collection of IWebServiceResource instances
*/
@Override
public Collection getWSDLResources() {
/*
* this list will collect all of the web service resources that are processed in this method so they can be returned from
* this method.
*/
final ArrayList resourcesCollection = new ArrayList();
/*
* This is the 'stack' of resources that remain to be processed. The code in the while below can add to this list in the
* while loop to emulate recursion. We load this stack initially with any resources that have been explicitly added to the
* builder by the user (these will most likely be WSDL documents).
*/
final LinkedList resourcesToProcessForDependencies = new LinkedList(resources);
while (!resourcesToProcessForDependencies.isEmpty()) {
final IWebServiceResource wsResourceToProcess = (IWebServiceResource)resourcesToProcessForDependencies.removeFirst();
resourcesCollection.add(wsResourceToProcess);
/*
* we check to see if the wsResourceToProcess is not null and whether it is an UnresolvableWebServiceResource.
* We dont try to process unresolvables because we cannot know what their content is.
*/
if (wsResourceToProcess != null && !(wsResourceToProcess instanceof UnresolvedWebServiceResource)) {
/*
* get the URI for the ws resource we are processing.
*/
final URI uri = URI.createFileURI(wsResourceToProcess.getFullPath());
/*
* use the handle to a resource set to resolve that uri to a physical resource.
*/
final Resource resourceToProcess = resourceSet.add(uri);
/*
* we are only concerned with resources that represent WSDL documents in this method.
*/
if (resourceSet.isWsdl(resourceToProcess)) {
final List roots = resourceToProcess.getContents();
/*
* iterate through the contents of the resource looking for 'Definitions'
*/
final Iterator iter = roots.iterator();
while (iter.hasNext()) {
final Object object = iter.next();
if (object instanceof Definitions) {
final Definitions defns = (Definitions)object;
/*
* We found a 'Definitions' object now lets iterate through the 'import' child objects and create web
* service resources for each adding them to the proper collections as we go.
*/
final List imports = defns.getImports();
final Iterator iter2 = imports.iterator();
while (iter2.hasNext()) {
IWebServiceResource wsr = null;
final Import theImport = (Import)iter2.next();
final URI locationUri = URI.createURI(theImport.getLocation());
final URI resolvedLocationUri = locationUri.resolve(uri); // resolve relative to the file ..
if (resolvedLocationUri != null && resolvedLocationUri.isFile()) {
final File f = new File(resolvedLocationUri.toFileString());
if (f.exists()) {
// Create a new web service resource for each ...
wsr = new FileSystemWebServiceResource(theImport.getNamespace(), f);
}
}
/*
* the physical resource file did not exist so we indicate such to the user by presenting them
* with this information. An UnresolvedWebServiceResources shows up in the UI as an error
* condition.
*/
if (wsr == null) {
wsr = new UnresolvedWebServiceResource(theImport.getNamespace());
}
wsr = addOrFind(wsr);
if (wsr instanceof AbstractWebServiceResource) {
((AbstractWebServiceResource)wsResourceToProcess).addReferencedResource(wsr);
}
/*
* add this resource to the stack so we can process things that it might depend on as well. A type
* of recursion. We protect against circular imports by checking first whether this resources is
* already in the collection of resources.
*/
if (emfResourceUriByWebServiceResource.get(wsr.getFullPath()) == null) {
emfResourceUriByWebServiceResource.put(wsr.getFullPath(), resolvedLocationUri);
resourcesToProcessForDependencies.add(wsr);
}
}
}
}
}
}
}
return resourcesCollection;
}
// =========================================================================
// Placing XSDs into the Workspace
// =========================================================================
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#getXsdDestinations()
* @since 4.2
*/
@Override
public Collection getXsdDestinations() {
List xsdResources = this.xsdWorkspaceResources;
if (!processedXsdResources) {
synchronized (xsdWorkspaceResourcesLock) {
// Discover all (directly and indirectly) referenced XSDs ...
final List xsdWsrTuples = doDiscoverReferencedXsds();
// keep track of destination names so we dont reuse
List usedNames = new ArrayList();
// Iterate through all of the referenced XSDs, and create the IWebServiceXsdResource objects ...
final Iterator iter = xsdWsrTuples.iterator();
while (iter.hasNext()) {
final XSDWebServiceResourceTuple tuple = (XSDWebServiceResourceTuple)iter.next();
final XSDSchema schema = tuple.getSchema();
final IWebServiceResource wsr = tuple.getResource();
final boolean inWorkspaceAlready = wsr instanceof WorkspaceFileWebServiceResource;
if (wsr.isWsdl() || (wsr.isXsd() && !inWorkspaceAlready)) {
final IWebServiceXsdResource wsXsdResource = doCreateWebServiceXsdResource(schema, wsr, usedNames);
if (wsXsdResource != null) {
this.xsdWorkspaceResources.add(wsXsdResource);
}
}
}
xsdResources = this.xsdWorkspaceResources;
processedXsdResources = true;
}
}
return xsdResources;
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#setDestinationPath(org.teiid.designer.webservice.IWebServiceXsdResource,
* org.eclipse.core.runtime.IPath)
* @since 4.2
*/
@Override
public void setDestinationPath( final IWebServiceXsdResource xsdResource,
final IPath workspacePathForXsd ) {
if (xsdResource instanceof IInternalWebServiceXsdResource) {
// See if it is different than the existing one ...
final IPath existing = xsdResource.getDestinationPath();
boolean match = false;
if (existing == null) {
if (workspacePathForXsd == null) {
match = true;
}
} else {
if (workspacePathForXsd == null) {
match = existing.segmentCount() == 0;
} else if( !existing.toFile().exists() ) {
match = false;
} else {
match = existing.makeAbsolute().equals(workspacePathForXsd.makeAbsolute());
}
}
if (!match) {
((IInternalWebServiceXsdResource)xsdResource).setDestinationPath(workspacePathForXsd.makeAbsolute());
}
// // If the path has changed, then mark the XSD resources as needing to be rediscovered ...
// if ( !match ) {
// synchronized(xsdWorkspaceResourcesLock) {
// this.xsdWorkspaceResources = null;
// }
// }
}
}
/**
* @param schema the XSD, never null
* @return
* @since 4.2
*/
public IWebServiceXsdResource doCreateWebServiceXsdResource( final XSDSchema schema,
final IWebServiceResource origResource,
List usedNames ) {
final WebServiceXsdResource result = new WebServiceXsdResource(schema, schema.getTargetNamespace(),
schema.eResource().getURI().toFileString());
try {
URI schemaUri = schema.eResource().getURI();
if (schemaUri.isFile()) {
schemaUri = URI.createFileURI(schemaUri.toFileString());
} else {
schemaUri = schema.eResource().getURI();
}
final URI wsdlUri = URI.createFileURI(origResource.getFullPath());
final IPath webServiceContainerPath = this.modelPath.removeLastSegments(1);
if (wsdlUri.equals(schemaUri)) {
/*
* This means that the schema represented by this schema object was embedded in the WSDL Document itself in the
* 'types' section and must contain schema content other than just 'imports'. In this case we need to 'make up' a
* name for this schema and save it as a seperate file so that the web service model can reference constructs
* contained in it. We have no model to represent a WSDL document so the schema elements must be moved into a
* seperate file to be referenced by other objects in the workspace.
*/
/*
* this will trim off the .wsdl file extension.
*/
final URI wsdlUriWOFileExtension = wsdlUri.trimFileExtension();
/*
* here we get the last segment which will be the wsdl file name without the file extension.
*/
final String name = wsdlUriWOFileExtension.lastSegment();
final String uniqueName = getUniqueName(name, usedNames);
final IPath uniqueSchemaNamePath = webServiceContainerPath.append(uniqueName
+ ResourceNameUtil.DOT_XSD_FILE_EXTENSION);
result.setDestinationPath(uniqueSchemaNamePath);
} else {
/*
* here we attempt to make the xsd uri relative to the WDSL uri.
*/
URI relativeUri = schemaUri.deresolve(wsdlUri);
// If this is not a file we assume it is a URL. Get the path and reassign the URI value
// as the path.
if (!relativeUri.isFile()) {
relativeUri = URI.createURI(relativeUri.path());
}
/*
* here we check to see if the 'relativized' path really turned out relative. If it did then we maintain the
* relative location from the WSDL file to the XSD in the workspace. Otherwise we simply put the XSD at the root
* of the project with its original name.
*/
String workspacePath = null;
if (relativeUri.isRelative()) {
workspacePath = relativeUri.toString();
} else {
workspacePath = schemaUri.lastSegment();
}
final IPath newPath = webServiceContainerPath.append(workspacePath);
result.setDestinationPath(newPath);
}
} catch (RuntimeException err) {
WebServicePlugin.Util.log(err);
}
return result;
}
/**
* this gets a new, unique name given a string and an existing collection The name will be incremented by adding "x", where x
* is an integer, until a unique name is found
*
* @param name the String to make unique
* @param collection the existing collection to compare against
* @return the unique name
*/
private String getUniqueName( String name,
Collection collection ) {
if (collection == null) {
collection = Collections.EMPTY_SET;
}
String result = name;
int incr = 1;
while (collection.contains(result)) {
result = name + incr;
incr++;
}
collection.add(result);
return result;
}
/**
* @param includeReferencedXsds true if all XSDs, including those referenced directly or indirectly by the XSDs, are to be
* included, or false if only the directly referenced XSDs should be included.
* @return the map of XSDSchema to the original IWebServiceResource where it came from ...
* @since 4.2
*/
protected List doDiscoverReferencedXsds() {
/*
* This list will be the accumulator for all schemas discovered in this method.
*/
final List wsResourceTuples = new LinkedList();
/*
* This List will contain the physical paths to all of the schemas that have been added to
* the wsResourceTuples. It will be used to prevent a schema from being added to the
* wsResourceTuplesList more than once.
*/
final List schemaPathsAlreadyAdded = new ArrayList();
for (Iterator iter = getResources().iterator(); iter.hasNext();) {
/*
* pull the first resource off of the Linked List stack.
*/
final IWebServiceResource wsr = (IWebServiceResource)iter.next();
/*
* Get the WebServiceResource that represents the actual physically resolved resource.
*/
final IWebServiceResource resolved = wsr.getLastResolvedResource();
/*
* if this WebServiceResource could not be resolved to a physical resource that exists, then we skip processing it.
*/
if (resolved == null) {
continue;
}
/*
* here we decide if we should go find WSDLs or XSD files that are referenced by the WebServiceResource we are
* currently processing.
*/
boolean findXsdSchema = false;
if (resolved.isWsdl()) {
findXsdSchema = true;
} else if (resolved.isXsd() && !(resolved instanceof WorkspaceFileWebServiceResource)) {
/*
* If the XSD is in the workspace already, then we assume that we dont need to go get any resources that it
* references. We assume that things that it references are in the workspace as well.
*/
findXsdSchema = true;
}
// If the resource is a WSDL or is a XSD that is outside of the workspace ...
if (findXsdSchema) {
// Create emf objects from the resource so that we can interrogate them.
final Resource emfResource = this.getEmfResource(wsr);
if (emfResource != null) {
final List roots = emfResource.getContents();
final Iterator rootIter = roots.iterator();
while (rootIter.hasNext()) {
/*
* here we iterate through all of the root content objects of the resource.
*/
final EObject root = (EObject)rootIter.next();
List schemas = new ArrayList();
/*
* if this resource represents a WSDL document.
*/
if (root instanceof Definitions) {
schemas.addAll(doDiscoverReferencedXsdsForWSDLResource((Definitions)root, emfResource));
} else if (root instanceof XSDSchema) {
schemas.addAll(processSchemas((XSDSchema)root, schemas, emfResource, new ArrayList()));
}
// Process what we've found ...
final Iterator schemaIter = schemas.iterator();
while (schemaIter.hasNext()) {
final XSDSchema schema = (XSDSchema)schemaIter.next();
if (schema != null) {
XSDWebServiceResourceTuple tuple = new XSDWebServiceResourceTuple(wsr, schema);
String schemaPath = schema.eResource().getURI().toString();
/*
* Here we check to see if the resource this scehma resides is a WSDL document.
* If this condition is true then we just go ahead and add this schema to the List of schemas to
* return from this method. We do this because this schema cannot be referred to by other
* schemas since it is embedded in a WSDL document. This prevents the problem that we are trying
* to avoid by checking for duplicates in the list of schema paths of having duplicate schemas
* in the list returned from this method.
*/
if (root instanceof Definitions) {
wsResourceTuples.add(tuple);
} else {
/*
* if the map does not already contain the schema we are working with,
* then add it to the List and the map so that we dont add it twice.
* otherwise we may wind up adding duplicate schemas to the list of schemas to be returned.
*/
if (!schemaPathsAlreadyAdded.contains(schemaPath)) {
schemaPathsAlreadyAdded.add(schemaPath);
wsResourceTuples.add(tuple);
}
}
}
}
}
}
}
}
return wsResourceTuples;
}
protected List doDiscoverReferencedXsdsForWSDLResource( Definitions wsdlDefinition,
Resource emfResource ) {
final List schemas = new ArrayList();
final Types types = wsdlDefinition.getTypes();
if (types != null) {
// Get all of the <schema> instances from the <types> element of the WSDL document.
final EList schemasFromTypes = types.getSchemas();
if (schemasFromTypes != null) {
final Iterator itSchemas = schemasFromTypes.iterator();
// Iterate through all of the schema objects in the WSDL types section.
while (itSchemas.hasNext()) {
final XSDSchemaImpl schemaTemp = (XSDSchemaImpl)itSchemas.next();
processSchemas(schemaTemp, schemas, emfResource, new ArrayList());
}
}
}
return schemas;
}
/**
* This method will return all of the referencing directives contained in the passed in XSDSchema object.
*
* @param schema the schema to inspect for referencing directives.
* @return a List of XSDSchemaDirective instances.
*/
protected List getSchemaImportsAndIncludes( XSDSchema schema ) {
final List referencingDirectives = new LinkedList();
for (Iterator iter = schema.eContents().iterator(); iter.hasNext();) {
final Object contentObject = iter.next();
if (contentObject instanceof XSDSchemaDirective) {
referencingDirectives.add(contentObject);
} else {
/*
* this code is here because all directives must come before any other entities in an XSD file, with the exception
* of annotations. This way we dont iterate through the rest of the entities in the XSD needlessly.
*/
if (!(contentObject instanceof XSDAnnotation)) {
break;
}
}
}
return referencingDirectives;
}
/**
* This method is used to recursively find all of the schemas that the passed in schemas depend on. The returned List will
* contain XSDSchema instances representing the referenced schemas that are referenced by the schema that is passed in.
*
* @param schema the schema for which to get references
* @param schemas This List is used in the recursion to 'collect' all of the schemas found recursively. Should be empty when
* this method is first called.
* @param referrringResource This this resource is the parent Resource that represents the schema
* @param schmaLocationToXSDImpl Another map used in the recursion. Pass in an empty map to call initially.
* @return A List of XSDSchema instances.
*/
protected List processSchemas( final XSDSchema schema,
final List schemas,
final Resource referrringResource,
final List schemaLocationsAlreadyAdded ) {
/*
* Iterate through the root contents of each of the <schema> elements in the <types> section of the WSDL doc.
*/
for (Iterator contents = schema.getContents().iterator(); contents.hasNext();) {
// defect 18274 - was throwing ClassCastException for certain WSDLs.
// Not all XSDSchemaContent objects are XSDSchemaContentImpls...
final XSDSchemaContent xsdSchemaContent = (XSDSchemaContent)contents.next();
/*
* This will handle both XSDImports and XSDIncludes so that we can process all schemas that are referenced by the
* given schema.
*/
if (xsdSchemaContent instanceof XSDSchemaDirective) {
final XSDSchemaDirective xsdImportImpl = (XSDSchemaDirective)xsdSchemaContent;
/*
* Get the schema location information from the xsd:import instance.
*/
String sSchemaLocation = xsdImportImpl.getSchemaLocation();
/*
* if the schema location value was not set on the XSDImportImpl, we try to get it from the underlying DOM
* element.
*/
if (sSchemaLocation == null) {
Node schemaObject = xsdImportImpl.getElement().getAttributes().getNamedItem(XSDConstants.SCHEMALOCATION_ATTRIBUTE);
if (schemaObject != null) {
sSchemaLocation = xsdImportImpl.getElement().getAttributes().getNamedItem(XSDConstants.SCHEMALOCATION_ATTRIBUTE).toString();
sSchemaLocation = trimNamedItem(sSchemaLocation, XSDConstants.SCHEMALOCATION_ATTRIBUTE);
} else {
// This is a namespace import.
continue;
}
}
/*
* create a URI from the schemaLocation value of the xsd:import element.
*/
URI uriSchemaLocation = URI.createURI(sSchemaLocation);
/*
* If that URI is relative to its referring resource, then we make it absolute for the purposes of creating a
* resource.
*/
if (uriSchemaLocation.isRelative()) {
/*
* create an absolute URI for the referrign resource.
*/
final URI referringResourceUri = referrringResource.getURI();
uriSchemaLocation = uriSchemaLocation.resolve(referringResourceUri);
}
/*
* we process further only if this schema has not already been added to the Map. This will prevent us from
* entering infinite recursion when two schemas both import eachother.
*/
if (!schemaLocationsAlreadyAdded.contains(uriSchemaLocation)) {
// load the schema, if it can be loaded
Resource resSchemaResource = null;
try {
/*
* Here we try to load the schema into a Model container from the physical location pointed to by the
* schema location in the xsd:import.
*/
resSchemaResource = ModelerCore.getModelContainer().getResource(uriSchemaLocation, true);
if (resSchemaResource == null) {
/*
* we were unable to load the schema from the schema location, therefore we add it to the list of
* referenced schemas as being 'NonResolvable'.
*/
NonResolvableXSDSchema xsdImpl = new NonResolvableXSDSchema(uriSchemaLocation);
if (!schemas.contains(xsdImpl)) {
schemas.add(xsdImpl);
}
String sMessage = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.ProblemLoadingXsdFromImport", URI.decode(uriSchemaLocation.toString())); //$NON-NLS-1$
/*
* we also add a 'diagnostic' which is an error message to be displayed to the user indicating the
* problem with this import.
*/
addDiagnosticToSchema(xsdImpl, sMessage);
}
} catch (CoreException theException) {
NonResolvableXSDSchema xsdImpl = new NonResolvableXSDSchema(uriSchemaLocation);
addDiagnosticToSchema(xsdImpl, theException.getLocalizedMessage());
if (!schemas.contains(xsdImpl)) {
schemas.add(xsdImpl);
}
} catch (Exception theException) {
NonResolvableXSDSchema xsdImpl = new NonResolvableXSDSchema(uriSchemaLocation);
addDiagnosticToSchema(xsdImpl, theException.getLocalizedMessage());
if (!schemas.contains(xsdImpl)) {
schemas.add(xsdImpl);
}
}
// add this schema to the schemas collection
if (resSchemaResource != null && resSchemaResource.getContents() != null
&& resSchemaResource.getContents().size() > 0) {
Object o = resSchemaResource.getContents().get(0);
if (o instanceof XSDSchema) {
final XSDSchema tempSchema = (XSDSchema)o;
/*
* We successfully resolved this schema so put it in the map before recursing to avoid circular
* reference problems with schemas that import eachother.
*/
schemaLocationsAlreadyAdded.add(uriSchemaLocation);
/*
* Everything was successful, so we add the XSDSchema instance content of the imported schema to the
* list of referenced schemas.
*/
if (!schemas.contains(o)) {
schemas.add(o);
}
/*
* now we recurse to find all of the schemas that this schema refers to.
*/
processSchemas(tempSchema, schemas, resSchemaResource, schemaLocationsAlreadyAdded);
}
}
}
} else if (xsdSchemaContent instanceof XSDAnnotation) {
/*
* This means that there still could be imports only in this schema so we simply ignore this content and continue
* to look through the root elements in the schema instance. all imports/includes must come before any other
* entity declarations in a schema. Annotations can be mixed in there with them as well.
*/
continue;
} else {
/*
* This means that there is content other than imports and annotations in this <schema> element. in that case we
* must add it as a 'schema' to the list of schemas that must be 'processed'. The schema content in this case will
* actually be spawned to a seperate file as a new schema document so the new web service model can refer to it.
* This is done because WSDL entities are not referenceable in the modeler workspace.
*/
if (!schemas.contains(schema)) {
schemas.add(schema);
}
break;
}
}
return schemas;
}
private void addDiagnosticToSchema( XSDSchemaImpl schema,
String sMessage ) {
XSDDiagnostic xsdDiagnostic = new XSDFactoryImpl().createXSDDiagnostic();
XSDDiagnosticSeverity severity = XSDDiagnosticSeverity.get(XSDDiagnosticSeverity.ERROR);
xsdDiagnostic.setSeverity(severity);
xsdDiagnostic.setMessage(sMessage);
xsdDiagnostic.setPrimaryComponent(schema);
xsdDiagnostic.setNode(schema.getElement());
Element theElement = schema.getElement();
xsdDiagnostic.setNode(theElement);
schema.getDiagnostics().add(xsdDiagnostic);
}
private String trimNamedItem( String sNamedItem,
String sId ) {
String sResult = sNamedItem;
String sMatchString = sId + "=" //$NON-NLS-1$
+ "\""; //$NON-NLS-1$
if (sResult.startsWith(sMatchString)) {
sResult = sResult.substring(sMatchString.length() - 1);
}
sResult = sResult.replace('\"', ' ');
sResult = sResult.trim();
return sResult;
}
public String getNamespaceFromImport( XSDSchema schema ) {
String sResultNamespace = null;
for (int i = 0; i < schema.eContents().size(); i++) {
Object o = schema.eContents().get(i);
if (o instanceof XSDImportImpl) {
XSDImportImpl xsdImport = (XSDImportImpl)o;
Element element = xsdImport.getElement();
if (element != null) {
NamedNodeMap nodeMap = element.getAttributes();
if (nodeMap != null) {
sResultNamespace = nodeMap.getNamedItem(XSDConstants.NAMESPACE_ATTRIBUTE).toString();
break;
}
}
}
}
return sResultNamespace;
}
// =========================================================================
// Validation
// =========================================================================
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#validateWSDLNamespaces()
* @since 5.0
*/
@Override
public IStatus validateWSDLNamespaces() {
final List problems = new LinkedList();
boolean foundErrors = false;
// Check that the model's parent resource is valid ...
if (this.parentResource == null) {
final String msg = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.MissingWebServiceModelLocation"); //$NON-NLS-1$
problems.add(new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, MISSING_PARENT_LOCATION, msg, null));
foundErrors = true;
} else {
if (!this.parentResource.exists()) {
final String msg = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.NonExistantWebServiceModelLocation"); //$NON-NLS-1$
problems.add(new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, PARENT_LOCATION_NONEXISTANT, msg, null));
foundErrors = true;
}
}
// Check that the model's path is valid ...
if (this.modelPath == null) {
final String msg = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.MissingWebServiceModelPath"); //$NON-NLS-1$
problems.add(new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, MISSING_MODEL_PATH, msg, null));
foundErrors = true;
}
// Check that the metamodel descriptor is valid ...
if (this.modelDescriptor == null) {
final String msg = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.MissingWebServiceModelDescriptor"); //$NON-NLS-1$
problems.add(new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, MISSING_DESCRIPTOR, msg, null));
foundErrors = true;
}
// Check that all namespaces resolved ...
List unresolved = new ArrayList();
Iterator itr = getResources().iterator();
while (itr.hasNext()) {
IWebServiceResource resource = (IWebServiceResource)itr.next();
if (!resource.isResolved()) {
final Object[] params = new Object[] {resource.getNamespace()};
final String msg = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.UnresolvedNamespace", params); //$NON-NLS-1$
unresolved.add(new Status(IStatus.ERROR, WebServicePlugin.PLUGIN_ID, UNRESOLVED_NAMESPACE, msg, null));
foundErrors = true;
}
}
if (!unresolved.isEmpty()) {
int size = unresolved.size();
if (size == 1) {
problems.add(unresolved.get(0));
} else if (size > 1) {
IStatus[] errors = new IStatus[size];
for (int i = 0; i < size; ++i) {
errors[i] = (IStatus)unresolved.get(i);
}
final Object[] params = new Object[] {new Integer(size)};
final String msg = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.MultipleUnresolvedNamespaces", params); //$NON-NLS-1$
problems.add(new MultiStatus(WebServicePlugin.PLUGIN_ID, UNRESOLVED_NAMESPACE, errors, msg, null));
}
}
return constructStatuses(problems, foundErrors);
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#validateWSDLNamespaces()
* @since 5.0
*/
@Override
public IStatus validateXSDNamespaces() {
final List problems = new LinkedList();
boolean foundErrors = false;
// Check that the destinations are all valid ...
final Iterator destIter = this.getXsdDestinations().iterator();
while (destIter.hasNext()) {
final IWebServiceXsdResource dest = (IWebServiceXsdResource)destIter.next();
final IStatus status = dest.isValid();
if (status.getSeverity() == IStatus.WARNING || status.getSeverity() == IStatus.ERROR) {
problems.add(status);
foundErrors = true;
}
}
return constructStatuses(problems, foundErrors);
}
/**
* Create and return an IStatus based
*
* @since 5.0
*/
public IStatus constructStatuses( List problems,
boolean foundErrors ) {
// Construct the statuses ...
IStatus result = null;
if (problems.size() == 0) {
final String msg = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.ReadyToGenerate"); //$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 {
final String msg = foundErrors ? WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.UnableToGenerate") : //$NON-NLS-1$
WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.ReadyToGenerate"); //$NON-NLS-1$
final MultiStatus multi = new MultiStatus(WebServicePlugin.PLUGIN_ID, MULTIPLE_MESSAGES, msg, null);
final Iterator iter = problems.iterator();
while (iter.hasNext()) {
final IStatus problem = (IStatus)iter.next();
multi.add(problem);
}
result = multi;
}
return result;
}
// =========================================================================
// Generation / Execution
// =========================================================================
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#getModelGenerator()
* @since 4.2
*/
@Override
public ModelGenerator getModelGenerator( boolean isNewModel ) {
// if ( this.generator == null ) {
// synchronized(this) {
// if ( this.generator == null ) {
// // Create the generator ...
// this.generator = doCreateModelGenerator();
// }
// }
// }
// return this.generator;
return doCreateModelGenerator(isNewModel);
}
/**
* Factory method for the ModelGenerator.
*
* @since 4.2
*/
protected ModelGenerator doCreateModelGenerator( boolean isNewModel ) {
final ModelGenerator generator = WebServicePlugin.createModelGenerator(this);
String desc = null;
// if ( this.wsdlFiles.size() != 0 ) {
// final StringBuffer sb = new StringBuffer();
// boolean first = true;
// final Iterator iter = this.wsdlFiles.keySet().iterator();
// while (iter.hasNext()) {
// final Object wsdlFile = iter.next();
//
// if (wsdlFile instanceof IFile) {
// sb.append(((IFile)wsdlFile).getFullPath());
// } else if (wsdlFile instanceof File) {
// sb.append(((File)wsdlFile).getAbsolutePath());
// } else {
// final Object[] params = new Object[] {wsdlFile};
// final String msg = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.FileIsNotWSDL",params); //$NON-NLS-1$
// throw new IllegalArgumentException(msg);
// }
//
// if ( !first ) {
// sb.append(", "); //$NON-NLS-1$
// }
// first = false;
// }
// final Object[] params = new Object[] {sb.toString()};
// desc = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.GenerateFromFollowingWSDL",params); //$NON-NLS-1$
// } else {
// desc = WebServicePlugin.Util.getString("BasicWebServiceModelBuilder.GenerateFromZeroWSDL"); //$NON-NLS-1$
// }
generator.setDescription(desc);
// Defect 23340
generator.setNewModelCase(isNewModel);
generator.setSaveAllBeforeFinish(this.saveAllBeforeFinish);
return generator;
}
@Override
public void setSaveAllBeforeFinish( boolean theDoSave ) {
this.saveAllBeforeFinish = theDoSave;
}
@Override
public List getAllNewResources() {
List resources = new ArrayList(10);
if (!xsdWorkspaceResources.isEmpty()) {
for (Iterator iter = xsdWorkspaceResources.iterator(); iter.hasNext();) {
IWebServiceXsdResource xsdRes = (IWebServiceXsdResource)iter.next();
IPath xsdPath = xsdRes.getDestinationPath();
IResource resource = null;
ModelWorkspaceItem wsItem = ModelWorkspaceManager.getModelWorkspaceManager().findModelWorkspaceItem(xsdPath,
IResource.FILE);
if (wsItem != null) {
resource = wsItem.getResource();
}
if (resource != null) {
resources.add(resource);
}
}
}
if (xmlModel != null) {
IResource resource = null;
ModelWorkspaceItem wsItem = ModelWorkspaceManager.getModelWorkspaceManager().findModelWorkspaceItem(xmlModel,
IResource.FILE);
if (wsItem != null) {
resource = wsItem.getResource();
}
if (resource != null) {
resources.add(resource);
}
}
if (modelPath != null) {
IResource resource = null;
ModelWorkspaceItem wsItem = ModelWorkspaceManager.getModelWorkspaceManager().findModelWorkspaceItem(modelPath,
IResource.FILE);
if (wsItem != null) {
resource = wsItem.getResource();
}
if (resource != null) {
resources.add(resource);
}
}
return resources;
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#setSelectedOperations(java.util.Collection)
* @since 5.0
*/
@Override
public void setSelectedOperations( Collection operations ) {
this.selectedWsdlOperations = operations;
}
/**
* @see org.teiid.designer.webservice.IWebServiceModelBuilder#getSelectedOperations()
* @since 5.0
*/
@Override
public Collection getSelectedOperations() {
return this.selectedWsdlOperations;
}
/**
* This class is used as a container for a Tuple of Web Service Resource and XSDSchema instance. It is a helper class to
* simplify the data structures required to map which Schemas have already been resolved
*/
public class XSDWebServiceResourceTuple {
private IWebServiceResource resource;
private XSDSchema schema;
public XSDWebServiceResourceTuple( IWebServiceResource resource,
XSDSchema schema ) {
this.schema = schema;
this.resource = resource;
}
public IWebServiceResource getResource() {
return this.resource;
}
public void setResource( IWebServiceResource resource ) {
this.resource = resource;
}
public XSDSchema getSchema() {
return this.schema;
}
public void setSchema( XSDSchema schema ) {
this.schema = schema;
}
}
}