/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.xml.factory; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; 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.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xsd.XSDComplexTypeDefinition; import org.eclipse.xsd.XSDElementDeclaration; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDTypeDefinition; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.workspace.ModelResource; import org.teiid.designer.core.workspace.ModelUtil; 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.xml.XmlDocument; import org.teiid.designer.metamodels.xml.XmlDocumentBuilderImpl; import org.teiid.designer.metamodels.xml.XmlDocumentFactory; import org.teiid.designer.metamodels.xml.XmlFragment; import org.teiid.designer.metamodels.xml.XmlRoot; import org.teiid.designer.metamodels.xml.util.XmlDocumentUtil; import org.teiid.designer.metamodels.xsd.XsdUtil; import org.teiid.designer.xml.PluginConstants; /** * VirtualDocumentModelPopulator * * @since 8.0 */ public class VirtualDocumentModelPopulator implements IDocumentsAndFragmentsPopulator, PluginConstants { private static final XmlFragment[] EMPTY_DOC_ARRAY = new XmlFragment[0]; private static final String TXN_NAME = Util.getString("VirtualDocumentModelPopulator.transactionName"); //$NON-NLS-1$ private static final String DOCUMENT = Util.getString("VirtualDocumentModelPopulator.document"); //$NON-NLS-1$ private static final String FRAGMENT = Util.getString("VirtualDocumentModelPopulator.fragment"); //$NON-NLS-1$ private static final String DOC_ERROR_MSG = Util.getString("VirtualDocumentModelPopulator.documentErrorMessage"); //$NON-NLS-1$ private static final String FRAG_ERROR_MSG = Util.getString("VirtualDocumentModelPopulator.fragmentErrorMessage"); //$NON-NLS-1$ private IFile schemaModel; // private XSDSchema schemaModelObject; private Collection unhandledModelImports = new HashSet(); private Collection allRootElements = new ArrayList(); private Collection selectedRootElements = new ArrayList(); private Collection allComplexTypes = new ArrayList(); private Collection selectedComplexTypes = new ArrayList(); private Set accumulatedDatatypes = new HashSet(); private int estimatedNodeCount; private boolean doNotBuildDuplicates = false; /** * Construct an instance of VirtualDocumentModelPopulator. * @param schemaModel */ public VirtualDocumentModelPopulator( IFile schemaModel ) { this.schemaModel = schemaModel; populateLists(); } /** * Construct an instance of VirtualDocumentModelPopulator. * @param initialRootElements */ public VirtualDocumentModelPopulator( List initialRootElements ) { // Let's set the schema model if (initialRootElements != null && !initialRootElements.isEmpty()) { EObject firstRoot = (EObject)initialRootElements.get(0); ModelResource mr = null; try { mr = ModelUtil.getModel(firstRoot); if (mr != null) { this.schemaModel = (IFile)mr.getUnderlyingResource(); } } catch (ModelWorkspaceException theException) { } } setSelectedDocuments(initialRootElements); } private void populateLists() { try { // Read the models ... final URI uri = URI.createFileURI(ModelUtil.getLocation(schemaModel).toString()); Resource resource = ModelerCore.getModelContainer().getResource(uri, true); for (Iterator iter = resource.getContents().iterator(); iter.hasNext();) { Object obj = iter.next(); if (obj instanceof XSDSchema) { // Accumulate Root ElementDeclarations List elements = ((XSDSchema)obj).getElementDeclarations(); Iterator elemIter = elements.iterator(); while (elemIter.hasNext()) { XSDElementDeclaration elemDecl = (XSDElementDeclaration)elemIter.next(); allRootElements.add(elemDecl); } // Accumulate ComplexTypes List types = ((XSDSchema)obj).getTypeDefinitions(); Iterator typeIter = types.iterator(); while (typeIter.hasNext()) { XSDTypeDefinition typeDefn = (XSDTypeDefinition)typeIter.next(); if (typeDefn instanceof XSDComplexTypeDefinition) { allComplexTypes.add(typeDefn); } } } } } catch (Exception e) { Util.log(e); } } /* (non-Javadoc) * @See org.teiid.designer.xml.internal.ui.wizards.IDocumentsAndFragmentsPopulator#getItem() */ @Override public Object getItem() { return this.schemaModel; } /* (non-Javadoc) * @See org.teiid.designer.xml.internal.ui.wizards.IDocumentsAndFragmentsPopulator#getItemName() */ @Override public String getItemName() { return schemaModel.getFullPath().toOSString(); } /* (non-Javadoc) * @See org.teiid.designer.xml.internal.ui.wizards.IDocumentsAndFragmentsPopulator#getInitialAvailableDocuments() */ @Override public Collection getInitialAvailableDocuments() { return allRootElements; } /* (non-Javadoc) * @See org.teiid.designer.xml.internal.ui.wizards.IDocumentsAndFragmentsPopulator#getInitialSelectedDocuments() */ @Override public Collection getSelectedDocuments() { return selectedRootElements; } /* (non-Javadoc) * @See org.teiid.designer.xml.internal.ui.wizards.IDocumentsAndFragmentsPopulator#getInitialAvailableFragments() */ @Override public Collection getInitialAvailableFragments() { return allComplexTypes; } /* (non-Javadoc) * @See org.teiid.designer.xml.internal.ui.wizards.IDocumentsAndFragmentsPopulator#getInitialSelectedFragments() */ @Override public Collection getSelectedFragments() { return selectedComplexTypes; } /* (non-Javadoc) * @See org.teiid.designer.xml.internal.ui.wizards.IDocumentsAndFragmentsPopulator#setSelectedDocuments(java.util.Collection) */ @Override public void setSelectedDocuments( Collection selectedItems ) { this.selectedRootElements = selectedItems; } /** * Set of Datatypes accumulated by the MappingClassFactory. These are used to determine SimpleTypes that need to be converted * to Enterprise Datatypes. * * @param accumulatedDatatypes */ public void setAccumulatedDatatypes( Set accumulatedDatatypes ) { this.accumulatedDatatypes = accumulatedDatatypes; } /** * Get the Set of Datatypes accumulated by the MappingClassFactory. * * @return accumulatedDatatypes */ public Set getAccumulatedDatatypes() { if (accumulatedDatatypes != null) { return this.accumulatedDatatypes; } // We don't want to return NULL here. return new HashSet(0); } /* (non-Javadoc) * @See org.teiid.designer.xml.internal.ui.wizards.IDocumentsAndFragmentsPopulator#setSelectedFragments(java.util.Collection) */ @Override public void setSelectedFragments( Collection selectedItems ) { this.selectedComplexTypes = selectedItems; } /* (non-Javadoc) * @See org.teiid.designer.xml.internal.ui.wizards.IDocumentsAndFragmentsPopulator#buildModel(org.eclipse.core.resources.IResource) */ @Override public XmlFragment[] buildModel( ModelResource modelResource, boolean buildEntireDocument, boolean buildMappingClasses, MappingClassBuilderStrategy strategy, final IProgressMonitor progressMonitor ) { List rv = new ArrayList(selectedComplexTypes.size() + selectedRootElements.size()); estimatedNodeCount = 0; final IProgressMonitor monitor = progressMonitor != null ? progressMonitor : new NullProgressMonitor(); // Ensure that the XSD resource used to build the XML document model is fully resolved try { final URI uri = URI.createFileURI(ModelUtil.getLocation(schemaModel).toString()); Resource xsdResource = ModelerCore.getModelContainer().getResource(uri, true); if (xsdResource != null) { XsdUtil.resolveSchemaDirectives(xsdResource); } } catch (Exception e) { Util.log(e); } XmlDocumentBuilderImpl builder = new XmlDocumentBuilderImpl(); XmlDocumentFactory factory = XmlDocumentFactory.eINSTANCE; ArrayList fragmentRoots = new ArrayList(); boolean startedTxn = ModelerCore.startTxn(false, false, TXN_NAME, this); boolean succeeded = false; try { // set the resource if it is available: Resource resource = (modelResource != null) ? modelResource.getEmfResource() : null; for (Iterator iter = selectedComplexTypes.iterator(); iter.hasNext();) { // Check for cancellation ... if (monitor.isCanceled()) { break; } XSDComplexTypeDefinition schemaComplexType = (XSDComplexTypeDefinition)iter.next(); try { String suggestedName = schemaComplexType.getName() + FRAGMENT; if (shouldBuildDocument(modelResource, suggestedName)) { XmlFragment fragment = factory.createXmlFragment(); fragment.setName(schemaComplexType.getName() + FRAGMENT); if (resource != null) { resource.getContents().add(fragment); } // endif XmlRoot docRoot = factory.createXmlRoot(); docRoot.setName(schemaComplexType.getName()); docRoot.setXsdComponent(schemaComplexType); fragment.setRoot(docRoot); if (buildEntireDocument) { estimatedNodeCount += builder.buildDocument(docRoot, monitor); fragmentRoots.add(docRoot); if (buildMappingClasses) { buildMappingClasses(fragment, strategy); // Force GC System.gc(); Thread.yield(); } } else { // not building entire document; leave it as BuildStatus incomplete XmlDocumentUtil.setIncomplete(docRoot, true); estimatedNodeCount++; } rv.add(fragment); } else { XmlFragment document = getExistingDocument(modelResource, suggestedName); if (document != null) { rv.add(document); } } } catch (Exception e) { String message = FRAG_ERROR_MSG + '\n' + schemaComplexType.getName(); Util.log(IStatus.ERROR, e, message); // MessageDialog.openError(null, FRAG_ERROR_TITLE, message); } } // force GC System.gc(); Thread.yield(); // swjTODO: load fragmentRoots into the builder before creating documents // try { // builder.buildXmlFragments(schemaModelObject); // } catch (Exception e) { // String message = FRAG_ERROR_MSG + '\n' + schemaModelObject.toString(); // ModelerXmlUiPlugin.Util.log(IStatus.ERROR, e, message); // MessageDialog.openError(null, FRAG_ERROR_TITLE, message); // } for (Iterator iter = selectedRootElements.iterator(); iter.hasNext();) { // Check for cancellation ... if (monitor.isCanceled()) { break; } XSDElementDeclaration schemaRootElement = (XSDElementDeclaration)iter.next(); try { String suggestedName = schemaRootElement.getName() + DOCUMENT; if (shouldBuildDocument(modelResource, suggestedName)) { XmlDocument document = factory.createXmlDocument(); if (resource != null) { ModelerCore.getModelEditor().addValue(resource, document, resource.getContents()); } String baseName = schemaRootElement.getName() + DOCUMENT; String newName = generateInitialUniqueName(document, baseName); document.setName(newName); XmlRoot docRoot = factory.createXmlRoot(); docRoot.setName(schemaRootElement.getName()); docRoot.setXsdComponent(schemaRootElement); document.setRoot(docRoot); if (buildEntireDocument) { estimatedNodeCount += builder.buildDocument(docRoot, monitor); if (buildMappingClasses) { buildMappingClasses(document, strategy); // Force GC System.gc(); Thread.yield(); } } else { // not building entire document; leave it as BuildStatus incomplete XmlDocumentUtil.setIncomplete(docRoot, true); estimatedNodeCount++; } rv.add(document); } else { XmlDocument document = getExistingDocument(modelResource, suggestedName); if (document != null) { rv.add(document); } } } catch (Exception e) { String message = DOC_ERROR_MSG + '\n' + schemaRootElement.getName(); Util.log(IStatus.ERROR, e, message); // MessageDialog.openError(null, DOC_ERROR_TITLE, message); } } // force GC System.gc(); Thread.yield(); succeeded = true; } catch (ModelWorkspaceException e) { Util.log(e); } finally { if (startedTxn) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } monitor.done(); // Force GC System.gc(); Thread.yield(); } unhandledModelImports = builder.getUnhandledModelImports(); // Clean up builder = null; if (modelResource != null) { try { modelResource.save(monitor, true); modelResource.getEmfResource().setModified(false); // Force GC System.gc(); Thread.yield(); } catch (ModelWorkspaceException e) { Util.log(e); } } return (XmlFragment[])rv.toArray(EMPTY_DOC_ARRAY); } private String generateInitialUniqueName( final EObject eObject, final String proposedName ) { String newName = proposedName; final EStructuralFeature nameFeature = ModelerCore.getModelEditor().getNameFeature(eObject); if (nameFeature != null && eObject.eResource() != null) { EList siblings = null; if (eObject.eContainer() == null) { siblings = eObject.eResource().getContents(); } else { siblings = eObject.eContainer().eContents(); } if (siblings != null && !siblings.isEmpty() && eObject.eGet(nameFeature) == null) { final Set siblingNames = new HashSet(); for (Iterator it = siblings.iterator(); it.hasNext();) { final EObject child = (EObject)it.next(); if (eObject.getClass().equals(child.getClass())) { siblingNames.add(child.eGet(nameFeature)); } } boolean foundUniqueName = false; int index = 1; while (!foundUniqueName) { if (siblingNames.contains(newName)) { newName = proposedName + String.valueOf(index++); } else { foundUniqueName = true; } } } } return newName; } @Override public Collection getUnhandledModelImports() { if (unhandledModelImports == null) { unhandledModelImports = new HashSet(); } return unhandledModelImports; } @Override public void buildMappingClasses( XmlFragment treeNode, MappingClassBuilderStrategy strategy ) { XmlRoot docRoot = treeNode.getRoot(); ITreeToRelationalMapper mapper = ModelMapperFactory.createModelMapper(treeNode); getAccumulatedDatatypes().addAll(new MappingClassFactory(mapper).generateMappingClasses(docRoot, strategy, true)); } @Override public int getLastEstimatedNodeCount() { return estimatedNodeCount; } /** * @param theDoNotBuildDuplicates The doNotBuildDuplicates to set. * @since 5.0 */ public void setDoNotBuildDuplicates( boolean theDoNotBuildDuplicates ) { this.doNotBuildDuplicates = theDoNotBuildDuplicates; } private boolean shouldBuildDocument( ModelResource modelResource, String newDocName ) { if (newDocName != null && doNotBuildDuplicates) { // Need to do a check for existing document with name List rootObjs = null; try { rootObjs = modelResource.getAllRootEObjects(); } catch (ModelWorkspaceException theException) { Util.log(theException); } if (rootObjs != null && !rootObjs.isEmpty()) { Iterator iter = rootObjs.iterator(); Object nextObj = null; while (iter.hasNext()) { nextObj = iter.next(); if (nextObj instanceof XmlDocument) { String docName = ModelerCore.getModelEditor().getName((EObject)nextObj); if (docName != null && docName.equalsIgnoreCase(newDocName)) { return false; } } } } return true; } return true; } private XmlDocument getExistingDocument( ModelResource modelResource, String newDocName ) { if (newDocName != null && doNotBuildDuplicates) { // Need to do a check for existing document with name List rootObjs = null; try { rootObjs = modelResource.getAllRootEObjects(); } catch (ModelWorkspaceException theException) { Util.log(theException); } if (rootObjs != null && !rootObjs.isEmpty()) { Iterator iter = rootObjs.iterator(); Object nextObj = null; while (iter.hasNext()) { nextObj = iter.next(); if (nextObj instanceof XmlDocument) { String docName = ModelerCore.getModelEditor().getName((EObject)nextObj); if (docName != null && docName.equalsIgnoreCase(newDocName)) { return (XmlDocument)nextObj; } } } } } return null; } }