/*
* 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.core.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.mapping.MappingRoot;
import org.eclipse.xsd.XSDPackage;
import org.eclipse.xsd.util.XSDResourceImpl;
import org.teiid.core.designer.ModelerCoreException;
import org.teiid.core.designer.id.IDGenerator;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.core.designer.util.ISafeReturningOperation;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.XsdObjectExtension;
import org.teiid.designer.core.resource.XResource;
import org.teiid.designer.core.workspace.ModelBufferImpl;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.core.workspace.ModelResourceImpl;
import org.teiid.designer.core.workspace.ModelUtil;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
import org.teiid.designer.core.workspace.Openable;
import org.teiid.designer.metamodels.core.Annotation;
import org.teiid.designer.metamodels.core.AnnotationContainer;
import org.teiid.designer.metamodels.core.CoreFactory;
import org.teiid.designer.metamodels.core.CorePackage;
import org.teiid.designer.metamodels.core.ModelAnnotation;
import org.teiid.designer.metamodels.core.ModelType;
import org.teiid.designer.metamodels.core.custom.impl.XsdModelAnnotationImpl;
import org.teiid.designer.metamodels.core.extension.XPackage;
import org.teiid.designer.metamodels.diagram.Diagram;
import org.teiid.designer.metamodels.diagram.DiagramContainer;
import org.teiid.designer.metamodels.diagram.DiagramFactory;
import org.teiid.designer.metamodels.diagram.DiagramPackage;
import org.teiid.designer.metamodels.transformation.FragmentMappingRoot;
import org.teiid.designer.metamodels.transformation.MappingClassSet;
import org.teiid.designer.metamodels.transformation.MappingClassSetContainer;
import org.teiid.designer.metamodels.transformation.SqlTransformationMappingRoot;
import org.teiid.designer.metamodels.transformation.TransformationContainer;
import org.teiid.designer.metamodels.transformation.TransformationFactory;
import org.teiid.designer.metamodels.transformation.TransformationMappingRoot;
import org.teiid.designer.metamodels.transformation.TransformationPackage;
import org.teiid.designer.metamodels.transformation.TreeMappingRoot;
/**
* The ModelContents provides access to a few of the large and distinct categories of the objects within a model, such as
* diagrams, transformation, and annotations. It is used by constructing an instance and supplying the
* {@link org.eclipse.emf.ecore.resource.Resource EMF Resource} for the model.
*
* @since 8.0
*/
public class ModelContents {
protected static final int DEFAULT_DIAGRAM_SIZE = 8;
protected static final int DEFAULT_TRANSFORMATION_SIZE = 3;
// private boolean registeredResource = true;
private final Resource resource;
private final List transientDiagrams;
private final boolean isXsd;
private DiagramFactory diagramFactory;
private TransformationFactory transformationFactory;
private CoreFactory coreFactory;
private DiagramContainer persistentDiagramContainer;
private TransformationContainer persistentTransformationsContainer;
private AnnotationContainer persistentAnnotationsContainer;
private MappingClassSetContainer persistentMappingClassSetContainer;
private final Object persistentDiagramLock = new Object();
private final Object persistentTransformationLock = new Object();
private final Object persistentAnnotationLock = new Object();
private final Object modelAnnotationLock = new Object();
private final Object persistentMappingClassContainerLock = new Object();
// cached here since it is not stored in the resource contents like in XMI models
private ModelAnnotation xsdModelAnnotation;
/**
* Obtain the ModelContents object that exists below a {@link ModelResource}. This may cause the resource to be
* {@link Openable#open(IProgressMonitor) opened} if it is not already.
*
* @param modelResource the model resource; may not be null
* @return the ModelContents object
* @throws ModelWorkspaceException if there is an error getting the contents from the resource.
*/
public static ModelContents getModelContents( final ModelResource modelResource ) throws ModelWorkspaceException {
CoreArgCheck.isNotNull(modelResource);
CoreArgCheck.isInstanceOf(ModelResourceImpl.class, modelResource);
// Get the ModelContents wrapper/utility from the resource ...
final ModelBufferImpl buffer = (ModelBufferImpl)((ModelResourceImpl)modelResource).getBuffer();
return buffer.getModelContents();
}
/**
* Construct an instance of ModelContents.
*
* @param resource the {@link Resource EMF resource} to which this object is to provide access; may not be null
*/
public ModelContents( final Resource resource ) {
super();
CoreArgCheck.isNotNull(resource);
this.resource = resource;
this.transientDiagrams = new LinkedList();
this.diagramFactory = null;
this.transformationFactory = null;
this.coreFactory = null;
this.isXsd = ModelUtil.isXsdFile(resource);
}
/**
* Provide a protected constructor for subclasses that may not have a Resource.
*/
protected ModelContents() {
super();
this.resource = null;
this.transientDiagrams = new LinkedList();
this.diagramFactory = null;
this.transformationFactory = null;
this.coreFactory = null;
this.isXsd = resource != null ? ModelUtil.isXsdFile(resource) : false;
}
protected DiagramFactory getDiagramFactory() {
if (this.diagramFactory == null) {
this.diagramFactory = DiagramPackage.eINSTANCE.getDiagramFactory();
}
return this.diagramFactory;
}
protected TransformationFactory getTransformationFactory() {
if (this.transformationFactory == null) {
this.transformationFactory = TransformationPackage.eINSTANCE.getTransformationFactory();
}
return this.transformationFactory;
}
protected CoreFactory getCoreFactory() {
if (this.coreFactory == null) {
this.coreFactory = CorePackage.eINSTANCE.getCoreFactory();
}
return this.coreFactory;
}
/**
* Returns resource held by this model contents. May be null;
*
* @return
* @since 4.3
*/
public Resource getResource() {
return this.resource;
}
// -------------------------------------------------------------------------
// Diagram-related methods
// -------------------------------------------------------------------------
/**
* Create a new diagram and add it to this resource, and specify whether the diagram is to be persisted.
*
* @param target the "target" for the diagram; null if the diagram's target is the "model" itself
* @param persistent true if the diagram is to be persisted in this resource, or false otherwise
* @return the new diagram
* @deprecated - use org.teiid.designer.core.util.ModelResourceContainerFactory.createDiagram() method NOTE: methods in
* ModelContents should not be concerned with transactions.
*/
@Deprecated
public Diagram createNewDiagram( final EObject target,
final boolean persistent ) {
if (isXsd) {
return null;
}
Diagram diagram = null;
// Start a txn and mark it as not significant (this operation can not be undone)
boolean startedTxn = ModelerCore.startTxn(false, null, this);
boolean succeeded = false;
try {
// Create the new diagram ...
diagram = getDiagramFactory().createDiagram();
if (target != null) {
// Use the non-null target if one was passed in
diagram.setTarget(target);
} else {
// Use the ModelAnnotation as the target. The convention is that diagrams that have a target
// of the "model" itself (which isn't an EObject) have a target of the ModelAnnotation.
// The reason for this is that transient diagrams don't have a resource, so getting the
// resource that contains the diagram for model-level diagrams (those that appear right under
// the model) requires having a target that is persistent. The ModelAnnotation is always
// persistent.
diagram.setTarget(this.getModelAnnotation());
}
// And add to the resource
doSetPersistent(diagram, persistent);
succeeded = true;
} finally {
// if we started the txn... commit it
if (startedTxn) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
return diagram;
}
/**
* Remove the specified diagram from this resource. This method works for persistent or transient diagrams; persistent
* diagrams can always just be removed from the {@link DiagramContainer}.
*
* @param diagram the diagram; may not be null
* @return true if the diagram was deleted from this resource, or false if it was not
*/
public boolean delete( final Diagram diagram ) {
if (diagram == null) {
return false;
}
// Try transient first
if (!this.transientDiagrams.remove(diagram)) {
// Not removed from transient, so try persistent ...
return ModelResourceContainerFactory.deleteDiagram(diagram);
}
return true;
}
/**
* Return whether the supplied diagram is considered transient.
*
* @param diagram the diagram
* @return true if the diagram is transient and will not be written out to the {@link Resource}, or false otherwise.
*/
public boolean isPersistent( final Diagram diagram ) {
return diagram.eContainer() != null;
}
/**
* Define whether the supplied diagram is considered persistent. This method has no effect if the diagram's persistence
* already matches <code>persistent</code>.
*
* @param diagram the diagram; may not be null
* @param persistent true if the diagram is to be persisted in this resource, or false otherwise
* @deprecated - use methods defined in org.teiid.designer.core.internal.workspace.ModelDiagrams
*/
@Deprecated
public void setPersistent( final Diagram diagram,
boolean persistent ) {
// If the diagram already matches the desired state ...
if (persistent == isPersistent(diagram)) {
return;
}
// It doesn't match, so set the persistence
doSetPersistent(diagram, persistent);
}
/**
* Utility method to actually make the diagram match the desired persistent state. This method does <i>not</i> check first
* whether the diagram is persistent; it simply performs the desired request.
*
* @deprecated - use methods defined in org.teiid.designer.core.internal.workspace.ModelDiagrams
*/
@Deprecated
protected void doSetPersistent( final Diagram diagram,
boolean persistent ) {
// And add to the resource
if (persistent) {
// Either to the actual persistent DiagramContainer. Note that this
// is done by setting the container on the diagram rather than adding
// the diagram to the container's getDiagram() list - this is because
// doing it this way ensures that the resource is notified as
// having unsaved changes
final DiagramContainer container = this.getDiagramContainer(true);
try {
ModelerCore.getModelEditor().addValue(container, diagram, container.getDiagram());
// diagram.setDiagramContainer(container);
} catch (ModelerCoreException err) {
ModelerCore.Util.log(IStatus.ERROR, err, err.getMessage());
diagram.setDiagramContainer(container);
}
} else {
// Or to the transient list
this.transientDiagrams.add(diagram);
}
}
public void addTransientDiagram( final Diagram diagram ) {
this.transientDiagrams.add(diagram);
}
public void removeTransientDiagram( final Diagram diagram ) {
this.transientDiagrams.remove(diagram);
}
/**
* Get the diagram objects associated with this resource. Diagrams are created using the
* {@link #createNewDiagram(EObject, boolean)} method. org.teiid.designer.core.ModelEditor ModelEditor}.
* <p>
* Return a {@link List} rather than a <code>Diagram[]</code>, since the
* content provider will have to merge these diagrams into the existing children of the
* target.
* </p>
*
* @return the {@link Diagram} instances that are in the model; never null, but possibly empty. This is a copy of the actual
* container, so modifications to the result will not be reflected in the model.
*/
public List getDiagrams() {
if (isXsd) {
return Collections.EMPTY_LIST;
}
final List results = createDiagramList();
// Add the persistent diagrams ...
final List persistentDiags = this.getPersistentDiagrams(false);
results.addAll(persistentDiags);
// Add the transient diagrams ...
results.addAll(this.transientDiagrams);
// These don't need to be ordered
return results;
}
/**
* Get the diagram objects associated with the supplied target model object. Diagrams are created using the
* {@link #createNewDiagram(EObject, boolean)} method.
* <p>
* Return a {@link List} rather than a <code>Diagram[]</code>, since the
* content provider will have to merge these diagrams into the existing children of the
* target.
* </p>
*
* @param target the target object
* @return the {@link Diagram} instances that are associated with the target object; never null, but possibly empty
*/
public List getDiagrams( final EObject target ) {
if (isXsd) {
return Collections.EMPTY_LIST;
}
final List results = createDiagramList();
// Replace the target if null
final EObject actualTarget = (target == null ? this.getModelAnnotation() : target);
// Add the persistent diagrams ...
final List persistentDiags = this.getPersistentDiagrams(false);
if (persistentDiags.size() != 0) {
addDiagramsForTarget(persistentDiags, actualTarget, results);
}
// Add the transient diagrams ...
if (this.transientDiagrams.size() != 0) {
addDiagramsForTarget(this.transientDiagrams, actualTarget, results);
}
// These don't need to be ordered
return results;
}
/**
* Utility method to create a new {@link List} instance that is used to return the list of Diagram instances.
*
* @return a new ArrayList with an initial available size of {@link #DEFAULT_DIAGRAM_SIZE}.
*/
protected List createDiagramList() {
return new ArrayList(DEFAULT_DIAGRAM_SIZE);
}
/**
* Utility method to return the DiagramContainer for persistent diagrams in this resource
*
* @return the DiagramContainer for this resource
*/
public DiagramContainer getDiagramContainer( final boolean createIfNeeded ) {
if (isXsd) {
return null;
}
if (this.persistentDiagramContainer == null) {
synchronized (this.persistentDiagramLock) {
if (this.persistentDiagramContainer == null) {
// Let's see if Diagram Container exists
this.persistentDiagramContainer = ModelResourceContainerFactory.getDiagramContainer(getAllRootEObjects());
// if it does not, then we can create one if resource != null
if (persistentDiagramContainer == null && resource != null) {
this.persistentDiagramContainer = ModelResourceContainerFactory.getDiagramContainer(resource,
createIfNeeded);
}
}
}
}
return this.persistentDiagramContainer;
}
/**
* Utility method to obtain the persistent diagrams for this resource
*
* @return the List of diagrams that are persistent in this resource
*/
protected List getPersistentDiagrams( final boolean createIfNeeded ) {
if (isXsd) {
return Collections.EMPTY_LIST;
}
final DiagramContainer container = getDiagramContainer(createIfNeeded);
if (container == null) {
return Collections.EMPTY_LIST;
}
return container.getDiagram();
}
/**
* Utility method to add to the supplied results list all of the diagram objects that have the supplied target.
*
* @param diagrams the list of {@link Diagram} instances to query; may not be null
* @param target the target
* @param results the list into which are placed all {@link Diagram} instances that have the supplied target; may not be null
*/
protected void addDiagramsForTarget( final List diagrams,
final EObject target,
final List results ) {
CoreArgCheck.isNotNull(diagrams);
CoreArgCheck.isNotNull(results);
final Iterator diagIter = diagrams.iterator();
while (diagIter.hasNext()) {
final Diagram diagram = (Diagram)diagIter.next();
if (diagram != null && isDiagramForTarget(diagram, target)) {
results.add(diagram);
}
}
}
/**
* Utility method to determine whether the supplied diagram has a target that matches the supplied object.
*
* @param diagram the {@link Diagram}; may not be null
* @param target the target
* @return true if the diagram has the supplied target, or false otherwise
*/
protected boolean isDiagramForTarget( final Diagram diagram,
final EObject target ) {
CoreArgCheck.isNotNull(diagram);
final Object actualTarget = diagram.getTarget();
if (actualTarget == null) {
return target == null; // only equal if target is null, too
}
return diagram.getTarget().equals(target);
}
// -------------------------------------------------------------------------
// Transformation-related methods
// -------------------------------------------------------------------------
/**
* Utility method to create a new {@link List} instance that is used to return the list of {@link TransformationMappingRoot}
* instances.
*
* @return a new ArrayList with an initial available size of {@link #DEFAULT_TRANSFORMATION_SIZE}.
*/
protected List createTransformationList() {
return new ArrayList(DEFAULT_TRANSFORMATION_SIZE);
}
/**
* Creates a new SQL transformation and add it to this resource.
*
* @param target the "target" for the transformation
* @return the new transformation
* @deprecated - use org.teiid.designer.core.util.ModelResourceContainerFactory.createSqlTransformationMappingRoot()
*/
@Deprecated
public SqlTransformationMappingRoot createSqlTransformation( final EObject target ) {
CoreArgCheck.isNotNull(target);
final SqlTransformationMappingRoot t = getTransformationFactory().createSqlTransformationMappingRoot();
t.getOutputs().add(target);
// Defect 18433 - BML 8/31/05 - Changed to not call addNewTransformation()
// This was not correctly adding the transformation using the ModelEditor.addValue() call
// Utilities were added to perform this work and insure proper transaction boundaries
// See org.teiid.designer.core.util.ModelResourceContainerFactory
return (SqlTransformationMappingRoot)addNewTransformation(target, t);
}
/**
* Creates a new SQL transformation and add it to this resource.
*
* @param target the "target" for the transformation
* @return the new transformation
* @deprecated - use org.teiid.designer.core.util.ModelResourceContainerFactory.createFragmentMappingRoot()
*/
@Deprecated
public FragmentMappingRoot createFragmentMapping( final EObject target ) {
CoreArgCheck.isNotNull(target);
final FragmentMappingRoot t = getTransformationFactory().createFragmentMappingRoot();
// Defect 18433 - BML 8/31/05 - Changed to not call addNewTransformation()
// This was not correctly adding the transformation using the ModelEditor.addValue() call
// Utilities were added to perform this work and insure proper transaction boundaries
// See org.teiid.designer.core.util.ModelResourceContainerFactory
return (FragmentMappingRoot)addNewTransformation(target, t);
}
/**
* Creates a new tree-mapping transformation and add it to this resource.
*
* @param target the "target" for the transformation
* @return the new transformation
* @deprecated - use org.teiid.designer.core.util.ModelResourceContainerFactory.createTreeMappingRoot()
*/
@Deprecated
public TreeMappingRoot createTreeMapping( final EObject target ) {
CoreArgCheck.isNotNull(target);
final TreeMappingRoot t = getTransformationFactory().createTreeMappingRoot();
// Defect 18433 - BML 8/31/05 - Changed to not call addNewTransformation()
// This was not correctly adding the transformation using the ModelEditor.addValue() call
// Utilities were added to perform this work and insure proper transaction boundaries
// See org.teiid.designer.core.util.ModelResourceContainerFactory
return (TreeMappingRoot)addNewTransformation(target, t);
}
/**
* Add the new transformation and add it to this resource.
*
* @param target the "target" for the transformation
* @return the new transformation
* @deprecated - use org.teiid.designer.core.util.ModelResourceContainerFactory methods for constructing mapping root
* objects.
*/
@Deprecated
public TransformationMappingRoot addNewTransformation( final EObject target,
final TransformationMappingRoot newMappingRoot ) {
CoreArgCheck.isNotNull(target);
// Set the target of the transformation
newMappingRoot.setTarget(target);
// NOTE: This WILL NOT create a Command that will end up in the UNDO Event's CompoundCommand.
// the ModelEditor.addValue() method insures this will happen.
getTransformationContainer(true).getTransformationMappings().add(newMappingRoot);
// Mark the resource as being modified, since the relationship is NOT bi-directional
setModified(true);
return newMappingRoot;
}
/**
* Get the transformation objects associated with the supplied model object that is the output of the transformations.
* Transformations are created using the {@link #createNewTransformation(EObject)} method.
* <p>
* Return a {@link List} rather than a <code>TransformationMappingRoot[]</code>, since the
* content provider will have to merge these transformations into the existing children
* of the target.
* </p>
*
* @param output the object that is the output of the transformation
* @return the {@link org.teiid.designer.metamodels.transformation.TransformationMappingRoot} instances that are associated with
* the output object; never null, but possibly empty
*/
public List getTransformationsForOutput( final EObject output ) {
final List results = createTransformationList();
// Add the persistent diagrams ...
final List transformations = new ArrayList(this.getTransformations());
if (transformations.size() != 0) {
addTransformationsForOutput(transformations, output, results);
}
// These don't need to be ordered
return results;
}
/**
* Get the transformation objects associated with the supplied model object that is the input source of the transformations.
* Transformations are created using the {@link #createNewTransformation(EObject)} method.
* <p>
* Return a {@link List} rather than a <code>TransformationMappingRoot[]</code>, since the
* ContentProvider will have to merge these transformations into the existing children
* of the target.
* </p>
*
* @param input the object that is the input of the transformation
* @return the {@link org.teiid.designer.metamodels.transformation.TransformationMappingRoot} instances that are associated with
* the input object; never null, but possibly empty
*/
public List getTransformationsForInput( final EObject input ) {
final List results = createTransformationList();
// Add the persistent diagrams ...
final List transformations = this.getTransformations();
if (transformations.size() != 0) {
addTransformationsForInput(transformations, input, results);
}
// These don't need to be ordered
return results;
}
/**
* Get the transformation objects associated with the supplied model object that is the target of the transformations.
* Transformations are created using the {@link #createNewTransformation(EObject)} method.
* <p>
* Return a {@link List} rather than a <code>TransformationMappingRoot[]</code>, since the
* content provider will have to merge these transformations into the existing children
* of the target.
* </p>
*
* @param output the object that is the output of the transformation
* @return the {@link org.teiid.designer.metamodels.transformation.TransformationMappingRoot} instances that are associated with
* the output object; never null, but possibly empty
*/
public List getTransformations( final EObject target ) {
final List results = createTransformationList();
// Add the persistent diagrams ...
final List transformations = this.getTransformations();
if (transformations.size() != 0) {
addTransformationsForTarget(transformations, target, results);
}
// These don't need to be ordered
return results;
}
/**
* Get the transformation objects associated with the supplied model object. Transformations are created using the
* {@link #createNewTransformation(EObject)} method.
* <p>
* Return a {@link List} rather than a <code>Diagram[]</code>, since the
* ContentProvider will have to merge these transformations into the existing children
* of the target.
* </p>
*
* @return the {@link org.teiid.designer.metamodels.transformation.TransformationMappingRoot} instances that are in the model;
* never null, but possibly empty. This list is modifiable; changes to it will be reflected in the model.
*/
public List getTransformations() {
final TransformationContainer container = this.getTransformationContainer(false);
if (container == null) {
return new ArrayList();
}
return container.getTransformationMappings();
}
/**
* Remove the specified transformation from this resource.
*
* @param transformation the transformation; may not be null
* @return true if the transformation was deleted from this resource, or false if it was not
*/
public boolean delete( final TransformationMappingRoot transformation ) {
if (ModelResourceContainerFactory.deleteTransformation(transformation)) {
// Mark the resource as being modified, since the relationship is NOT bi-directional
setModified(true);
return true;
}
return false;
}
protected void setModified( final boolean modified ) {
this.resource.setModified(modified);
}
protected URI getUri() {
return this.resource.getURI();
}
/**
* Utility method to return the TransformationContainer for transformation in this resource
*
* @return the TransformationContainer for this resource
*/
public TransformationContainer getTransformationContainer( final boolean createIfNeeded ) {
if (this.persistentTransformationsContainer == null) {
synchronized (this.persistentTransformationLock) {
if (this.persistentTransformationsContainer == null) {
// Let's see if Transformations Container exists
this.persistentTransformationsContainer = ModelResourceContainerFactory.getTransformationContainer(getAllRootEObjects());
// if it does not, then we can create one if resource != null
if (persistentTransformationsContainer == null && resource != null) {
this.persistentTransformationsContainer = ModelResourceContainerFactory.getTransformationContainer(resource,
createIfNeeded);
}
}
}
}
return this.persistentTransformationsContainer;
}
/**
* Utility method to add to the supplied results list all of the transformation objects that have the supplied output.
*
* @param transformations the list of {@link TransformationMappingRoot} instances to query; may not be null
* @param output the output
* @param results the list into which are placed all {@link TransformationMappingRoot} instances that have the supplied
* output; may not be null
*/
protected void addTransformationsForOutput( final List transformations,
final EObject output,
final List results ) {
CoreArgCheck.isNotNull(transformations);
CoreArgCheck.isNotNull(results);
final Iterator diagIter = transformations.iterator();
while (diagIter.hasNext()) {
final MappingRoot mappingRoot = (MappingRoot)diagIter.next();
if (mappingRoot != null && isOutputOfTransformation(mappingRoot, output)) {
results.add(mappingRoot);
}
}
}
/**
* Utility method to add to the supplied results list all of the transformation objects that have the supplied input.
*
* @param transformations the list of {@link TransformationMappingRoot} instances to query; may not be null
* @param input the input
* @param results the list into which are placed all {@link TransformationMappingRoot} instances that have the supplied
* output; may not be null
*/
protected void addTransformationsForInput( final List transformations,
final EObject input,
final List results ) {
CoreArgCheck.isNotNull(transformations);
CoreArgCheck.isNotNull(results);
final Iterator diagIter = transformations.iterator();
while (diagIter.hasNext()) {
final MappingRoot mappingRoot = (MappingRoot)diagIter.next();
if (mappingRoot != null && isInputOfTransformation(mappingRoot, input)) {
results.add(mappingRoot);
}
}
}
/**
* Utility method to add to the supplied results list all of the transformation objects that have the supplied target.
*
* @param transformations the list of {@link TransformationMappingRoot} instances to query; may not be null
* @param output the output
* @param results the list into which are placed all {@link TransformationMappingRoot} instances that have the supplied
* output; may not be null
*/
protected void addTransformationsForTarget( final List transformations,
final EObject target,
final List results ) {
CoreArgCheck.isNotNull(transformations);
CoreArgCheck.isNotNull(results);
// Make copy of transformations
// Needed to prevent concurrent modifications
List copyOfTransforms = new ArrayList(transformations);
final Iterator transformIter = copyOfTransforms.iterator();
while (transformIter.hasNext()) {
final MappingRoot mappingRoot = (MappingRoot)transformIter.next();
if (mappingRoot != null && mappingRoot instanceof TransformationMappingRoot) {
final TransformationMappingRoot tmr = (TransformationMappingRoot)mappingRoot;
// If the target of the mapping root is null
if (tmr.getTarget() == null) {
if (target == null) {
// And the target is null, then it's a match
results.add(tmr);
}
// Else this is not a match, so go on to the next one ...
break;
}
// the root's target is non-null, so compare to the target ...
if (tmr.getTarget().equals(target)) {
// Match, so add to the results
results.add(mappingRoot);
}
}
}
}
/**
* Utility method to determine whether the supplied transformation has an output that matches the supplied object.
*
* @param mappingRoot the {@link MappingRoot}; may not be null
* @param output the output
* @return true if the transformation has the supplied output, or false otherwise
*/
protected boolean isOutputOfTransformation( final MappingRoot mappingRoot,
final EObject output ) {
CoreArgCheck.isNotNull(mappingRoot);
return mappingRoot.getOutputs().contains(output);
}
/**
* Utility method to determine whether the supplied transformation has an input that matches the supplied object.
*
* @param mappingRoot the {@link MappingRoot}; may not be null
* @param output the output
* @return true if the transformation has the supplied input, or false otherwise
*/
protected boolean isInputOfTransformation( final MappingRoot mappingRoot,
final EObject input ) {
CoreArgCheck.isNotNull(mappingRoot);
return mappingRoot.getInputs().contains(input);
}
// -------------------------------------------------------------------------
// Annotation-related methods
// -------------------------------------------------------------------------
/**
* Get the annotation associated with the supplied model object. Annotations are created using the
* {@link #createNewAnnotation(EObject)} method.
* <p>
*
* @param annotatedObject the object that is annotated
* @return the {@link Annotation} instance, or null if there is no Annotation for the supplied object
*/
public ModelAnnotation getModelAnnotation() {
if (this.isXsd) {
if (this.xsdModelAnnotation != null) {
return this.xsdModelAnnotation;
}
} else {
// check for model annotation as a root eObject for the resource
// Make a copy of the root objects (to prevent concurrent mod exception)
final List rootObjs = new ArrayList(getAllRootEObjects());
// Look under the roots for the ModelAnnotation object
for (final Iterator i = rootObjs.iterator(); i.hasNext();) {
final EObject rootObj = (EObject)i.next();
if (rootObj instanceof ModelAnnotation) {
return (ModelAnnotation)rootObj;
}
}
}
// Create a new model annotation
return (ModelAnnotation)TransactionUtil.executeNonUndoable(new ISafeReturningOperation() {
@Override
public Object execute() {
return createModelAnnotation();
}
}, this);
}
ModelAnnotation createModelAnnotation() {
synchronized (this.modelAnnotationLock) {
ModelAnnotation newModelAnnotation;
if (this.isXsd) {
// Defect 12555: New up a XsdModelAnnotationImpl and populate it
newModelAnnotation = new XsdModelAnnotationImpl(this.resource);
newModelAnnotation.setPrimaryMetamodelUri(XSDPackage.eNS_URI);
newModelAnnotation.setModelType(ModelType.TYPE_LITERAL);
newModelAnnotation.setMaxSetSize(0);
newModelAnnotation.setSupportsDistinct(false);
newModelAnnotation.setSupportsJoin(false);
newModelAnnotation.setSupportsOrderBy(false);
newModelAnnotation.setSupportsOuterJoin(false);
newModelAnnotation.setSupportsWhereAll(false);
newModelAnnotation.setVisible(false);
// create a UUID and store it in the ID maps in case an ID-related lookup of this annotation is done later
if (this.resource instanceof XResource) {
this.xsdModelAnnotation = newModelAnnotation;
((XResource)this.resource).setUuid(newModelAnnotation, IDGenerator.getInstance().create().toString());
}
if (this.resource instanceof XSDResourceImpl) {
try {
final XSDResourceImpl xsdResource = (XSDResourceImpl)this.resource;
if (xsdResource.getSchema() != null) {
XPackage extPackage = XsdObjectExtension.getExtensionPackage(xsdResource);
if (extPackage != null) {
newModelAnnotation.setExtensionPackage(extPackage);
}
}
} catch (ModelerCoreException err) {
ModelerCore.Util.log(IStatus.ERROR, err, err.getMessage());
}
}
} else {
// If there is no model annotation, then create one ...
newModelAnnotation = getCoreFactory().createModelAnnotation();
getAllRootEObjects().add(0, newModelAnnotation);
// Mark the resource as having changed
setModified(true);
}
return newModelAnnotation;
}
}
/**
* Create a new annotation and add it to this resource.
*
* @param annotatedObject the object for which an annotation is to be created; should be null only if the annotation is for
* the {@link ModelAnnotation model itself}.
* @return the new annotation
* @deprecated - use org.teiid.designer.core.util.ModelResourceContainerFactory.createNewAnnotation(target,
* annotationContainer)
*/
@Deprecated
public Annotation createNewAnnotation( final EObject annotatedObject ) {
return ModelResourceContainerFactory.createNewAnnotation(annotatedObject, getAnnotationContainer(true));
}
/**
* Get the annotation associated with the supplied model object. Annotations are created using the
* {@link #createNewAnnotation(EObject)} method.
* <p>
*
* @param annotatedObject the object that is annotated
* @return the {@link Annotation} instance, or null if there is no Annotation for the supplied object
*/
public Annotation getAnnotation( final EObject annotatedObject ) {
if (annotatedObject == null) {
return null;
}
final AnnotationContainer container = getAnnotationContainer(false);
if (container == null) {
return null;
}
final Annotation existing = container.findAnnotation(annotatedObject);
if (existing != null) {
return existing;
}
//
// final Iterator iter = new ArrayList(getAnnotations()).iterator();
// while (iter.hasNext()) {
// final Annotation annotation = (Annotation)iter.next();
// if ( annotation.getAnnotatedObject() == annotatedObject ) {
// return annotation;
// }
// }
return null;
}
/**
* Get the transformation objects associated with the supplied model object. Transformations are created using the
* {@link #createNewTransformation(EObject)} method.
* <p>
* Return a {@link List} rather than a <code>Diagram[]</code>, since the
* content provider will have to merge these transformations into the existing children
* of the target.
* </p>
*
* @return the {@link org.teiid.designer.metamodels.transformation.TransformationMappingRoot} instances that are in the model;
* never null, but possibly empty. This list is modifiable; changes to it will be reflected in the model.
*/
public List getAnnotations() {
final AnnotationContainer container = getAnnotationContainer(false);
if (container == null) {
return Collections.EMPTY_LIST;
}
return container.getAnnotations();
}
/**
* Remove the specified annotation from this resource.
*
* @param annotation the annotation; may not be null
* @return true if the annotation was deleted from this resource, or false if it was not
*/
public boolean delete( final Annotation annotation ) {
return ModelResourceContainerFactory.deleteAnnotation(annotation);
}
/**
* Utility method to return the TransformationContainer for transformation in this resource
*
* @return the TransformationContainer for this resource
*/
public AnnotationContainer getAnnotationContainer( final boolean createIfNeeded ) {
if (isXsd) {
return null;
}
if (this.persistentAnnotationsContainer == null) {
synchronized (this.persistentAnnotationLock) {
if (this.persistentAnnotationsContainer == null) {
// Let's see if Annotations Container exists
this.persistentAnnotationsContainer = ModelResourceContainerFactory.getAnnotationContainer(getAllRootEObjects());
// if it does not, then we can create one if resource != null
if (persistentAnnotationsContainer == null && resource != null) {
this.persistentAnnotationsContainer = ModelResourceContainerFactory.getAnnotationContainer(resource,
createIfNeeded);
}
}
}
}
return this.persistentAnnotationsContainer;
}
// -------------------------------------------------------------------------
// MappingClassSet-related methods
// -------------------------------------------------------------------------
/**
* Create a new {@link MappingClassSet} and add it to this resource.
*
* @param target the "target" for the mapping class sets; may not be null
* @return the new MappingClassSet object
* @deprecated - use org.teiid.designer.core.util.ModelResourceContainerFactory.getMappingClassSet() method
*/
@Deprecated
public MappingClassSet createNewMappingClassSet( final EObject target ) {
CoreArgCheck.isNotNull(target);
// Create the new mapping class set ...
final MappingClassSet mcSet = getTransformationFactory().createMappingClassSet();
mcSet.setTarget(target);
// And add to the resource.
// Defect 18433 - BML 8/31/05 - The following call was adding confusion to the transaction
// boundaries. A new utility class was created to correctly handle creation of this object
// See org.teiid.designer.core.util.ModelResourceContainerFactory
getMappingClassSetContainer(true).getMappingClassSets().add(mcSet);
return mcSet;
}
/**
* Get the {@link MappingClassSet} objects associated with the supplied target model object. MappingClassSets are created
* using the {@link #createNewMappingClassSet(EObject)} method.
*
* @param target the target object; may be null, meaning find all {@link MappingClassSet} instances that have no target
* @return the {@link MappingClassSet} instances that are associated with the target object; never null, but possibly empty
*/
public List getMappingClassSets( final EObject target ) {
final List result = new ArrayList();
final Iterator iter = new ArrayList(getMappingClassSets()).iterator();
while (iter.hasNext()) {
final MappingClassSet mcSet = (MappingClassSet)iter.next();
if (mcSet.getTarget() != null && mcSet.getTarget().equals(target)) {
result.add(mcSet);
}
}
return result;
}
/**
* Get all the {@link MappingClassSet} objects known by this resource. MappingClassSets are created using the
* {@link #createNewMappingClassSet(EObject)} method.
*
* @return the {@link MappingClassSet} instances for this resource; never null, but possibly empty
*/
public List getMappingClassSets() {
final MappingClassSetContainer container = getMappingClassSetContainer(false);
if (container == null) {
return Collections.EMPTY_LIST;
}
return container.getMappingClassSets();
}
/**
* Remove the specified {@link MappingClassSet} from this resource.
*
* @param mappingClassSet the {@link MappingClassSet} to be deleted; may not be null
* @return true if the {@link MappingClassSet} was deleted from this resource, or false if it was not
*/
public boolean delete( final MappingClassSet mappingClassSet ) {
return ModelResourceContainerFactory.deleteMappingClassSet(mappingClassSet);
}
/**
* Utility method to return the TransformationContainer for transformation in this resource
*
* @return the TransformationContainer for this resource
*/
public MappingClassSetContainer getMappingClassSetContainer( final boolean createIfNeeded ) {
if (this.persistentMappingClassSetContainer == null) {
synchronized (this.persistentMappingClassContainerLock) {
if (this.persistentMappingClassSetContainer == null) {
// Let's see if Annotations Container exists
this.persistentMappingClassSetContainer = ModelResourceContainerFactory.getMappingClassSetContainer(getAllRootEObjects());
// if it does not, then we can create one if resource != null
if (persistentMappingClassSetContainer == null && resource != null) {
this.persistentMappingClassSetContainer = ModelResourceContainerFactory.getMappingClassSetContainer(resource,
createIfNeeded);
}
}
}
}
return this.persistentMappingClassSetContainer;
}
// -------------------------------------------------------------------------
// Other helper methods
// -------------------------------------------------------------------------
/**
* Return all of the root objects.
*
* @return the list of all root objects in the resource. This is is modifiable.
*/
public List getAllRootEObjects() {
return this.resource.getContents();
}
/**
* Return only those root objects that are primary objects. Non-primary objects (i.e., secondary objects) include:
* <ul>
* <li>{@link DiagramContainer}</li>
* <li>{@link TransformationContainer}</li>
* <li>{@link AnnotationContainer}</li>
* <li>{@link ModelAnnotation}</li>
* <li>{@link MappingClassSetContainer}</li>
* </ul>
*/
public List getEObjects() {
// Create a copy of the complete list of roots ...
final List allRoots = getAllRootEObjects();
final LinkedList roots = new LinkedList();
// Add only the primary objects objects ...
final Iterator iter = allRoots.iterator();
while (iter.hasNext()) {
final Object rootObj = iter.next();
// See if the object is a "secondary" object ...
if (rootObj instanceof DiagramContainer || rootObj instanceof TransformationContainer
|| rootObj instanceof AnnotationContainer || rootObj instanceof ModelAnnotation
|| rootObj instanceof MappingClassSetContainer) {
continue;
}
// It's not secondary, so add it ...
roots.add(rootObj);
}
return roots;
}
// /**
// * @return Returns the registeredResource.
// * @since 4.3
// */
// public boolean isRegisteredResource() {
// return this.registeredResource;
// }
//
//
// /**
// * @param registeredResource The registeredResource to set.
// * @since 4.3
// */
// public void setRegisteredResource(boolean registeredResource) {
// this.registeredResource = registeredResource;
// }
}