/* * 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.container; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; import java.util.Collection; import java.util.Collections; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.emf.common.command.BasicCommandStack; import org.eclipse.emf.common.command.Command; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.Resource.Factory.Registry; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.URIConverter; import org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl; import org.eclipse.emf.ecore.util.EContentAdapter; import org.eclipse.emf.edit.command.CommandParameter; import org.eclipse.emf.edit.command.SetCommand; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emf.edit.domain.IEditingDomainProvider; import org.eclipse.emf.edit.provider.ChangeNotifier; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.xsd.XSDPackage; import org.teiid.core.designer.CoreModelerPlugin; import org.teiid.core.designer.ModelerCoreException; import org.teiid.core.designer.ModelerCoreRuntimeException; import org.teiid.core.designer.event.EventBroker; import org.teiid.core.designer.id.InvalidIDException; import org.teiid.core.designer.id.ObjectID; import org.teiid.core.designer.id.UUID; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.core.designer.util.RunnableState; import org.teiid.designer.core.ModelEditorImpl; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.metamodel.MetamodelDescriptor; import org.teiid.designer.core.metamodel.MetamodelRegistry; import org.teiid.designer.core.resource.EmfResourceSetImpl; import org.teiid.designer.core.resource.XResource; import org.teiid.designer.core.transaction.UndoableListener; import org.teiid.designer.core.transaction.UnitOfWork; import org.teiid.designer.core.transaction.UnitOfWorkImpl; import org.teiid.designer.core.transaction.UnitOfWorkProvider; import org.teiid.designer.core.transaction.UnitOfWorkProviderImpl; import org.teiid.designer.core.types.DatatypeManager; import org.teiid.designer.core.util.ExternalResourceImportsHelper; import org.teiid.designer.core.util.ProcessedNotificationResult; /** * This class represents a Container implementation for the MetaBase Toolkit that encapsulates the Eclipse Modeling Framework * (EMF). * * @since 8.0 */ public class ContainerImpl implements Container, IEditingDomainProvider { private static final ResourceSet[] EMPTY_RESOURCE_SET_ARRAY = new ResourceSet[0]; // ############################################################################################################################ // # Constants # // ############################################################################################################################ // state flags public static final int UNSTARTED = RunnableState.UNSTARTED; public static final int STARTING = RunnableState.STARTING; public static final int STARTED = RunnableState.STARTED; public static final int STOPPING = RunnableState.STOPPING; public static final int STOPPED = RunnableState.STOPPED; public static final int FAILED = RunnableState.FAILED; // ############################################################################################################################ // # Variables # // ############################################################################################################################ private UnitOfWorkProvider emfTransactionProvider; private ResourceSet resourceSet; private MetamodelRegistry metamodelRegistry; private MultiStatus status; private final ObjectManager objectManager; private DatatypeManager datatypeManager; private Map options; /** * The started/shutdown state of the container. * * @since 3.1 */ private RunnableState state; /** * The name of the container. The name may be changed only if the container has not been started. * * @since 3.1 */ private String name; /** * The EventBroker object for this Container. This implementation simply manages and maintains the reference, although the * broker's {@link EventBroker#shutdown()} method is called during the AbstractContainer's {@link #shutdown()}. * * @since 3.1 */ private ChangeNotifier changeNotifier; private EObjectFinder finder; private ResourceFinder resourceFinder; private EditingDomain editingDomain; private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); // ############################################################################################################################ // # Constructors # // ############################################################################################################################ /** * Constructor for AbstractContainer. * * @since 3.1 */ public ContainerImpl() { this.objectManager = new ObjectManagerImpl(this); initializeDefaults(); } // ############################################################################################################################ // # Methods # // ############################################################################################################################ @Override public void addPropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(listener); } @Override public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(propertyName, listener); } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(listener); } /* (non-Javadoc) * @see com.metamatrix.modeler.core.PropertyChangePublisher#removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener) */ @Override public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(propertyName, listener); } /** * Returns a resource for the URI that either already exists, is new but represents an existing file, or is new and represents * a brand-new file. * * @param resourceSet the resource set; may not be null * @param uri the URI for the resource; may not be null * @param runAfterCreation a Runnable that should be * @return the ResourceAction containing the Resource for the URI (which is never null) and a flag stating whether the * resource was created * @throws ModelerCoreException if the resource cannot be loaded or created */ public static ResourceAction getOrCreateResource( final ResourceSet resourceSet, final URI uri ) throws ModelerCoreException { CoreArgCheck.isNotNull(uri); // See if the resource exists already ... final Resource existingResource = resourceSet.getResource(uri, false); // returns null if non-existant if (existingResource != null) { // Found an existing resource, so just return it return new ResourceAction(existingResource, false); } // The resource doesn't already exist in the ResourceSet, so try loading it first if (!uri.isFile()) { final Object[] params = new Object[] {URI.decode(uri.toString())}; final String msg = ModelerCore.Util.getString("ContainerImpl.URI_is_not_a_file_and_cannot_be_openned_as_a_resource", params); //$NON-NLS-1$ throw new ModelerCoreException(msg); } final File file = new File(uri.toFileString()); if (file.canRead() && file.exists() && file.length() != 0) { // If the file is not empty ... try { // Try opening the existing file ... return new ResourceAction(resourceSet.getResource(uri, true), false); } catch (DuplicateResourceException dre) { // Caught a duplicate resource exception, so propogate and don't log ... throw dre; } catch (Throwable t) { final Object[] params = new Object[] {URI.decode(uri.toString())}; final String msg = ModelerCore.Util.getString("ContainerImpl.Unable_to_open_the_resource", params); //$NON-NLS-1$ throw new ModelerCoreException(t, msg); } } // Could not load an existing file, so try creating the file ... try { Resource newResource = resourceSet.createResource(uri); return new ResourceAction(newResource, true); } catch (DuplicateResourceException dre) { // Caught a duplicate resource exception, so propogate and don't log ... throw dre; } catch (Throwable t) { final Object[] params = new Object[] {URI.decode(uri.toString())}; final String msg = ModelerCore.Util.getString("ContainerImpl.Unable_to_create_the_resource", params); //$NON-NLS-1$ throw new ModelerCoreException(t, msg); } } /* (non-Javadoc) * @See org.teiid.designer.core.container.Container#getOrCreateResource(org.eclipse.emf.common.util.URI) */ @Override public Resource getOrCreateResource( final URI uri ) throws ModelerCoreException { final ResourceAction action = ContainerImpl.getOrCreateResource(this, uri); return action.getResource(); } /** * Return true if state == started * * @author Lance Phillips * @since 3.1 */ public boolean isStarted() { return this.state.isState(STARTED); } /** * Return true if state == stopped * * @author Lance Phillips * @since 3.1 */ public boolean isStopped() { return this.state.isState(STOPPED); } /** * Add the given listener to the emfTransactionProvider's UndoableListener list * * @param listener */ @Override public void addUndoableEditListener( UndoableListener listener ) { this.emfTransactionProvider.addUndoableEditListener(listener); } /** * Remove the given listener from the emfTransactionProvider's UndoableListener list * * @param listener */ @Override public void removeUndoableEditListener( UndoableListener listener ) { this.emfTransactionProvider.removeUndoableEditListener(listener); } /** * Determine whether the supplied name is considered valid. This method considers all names to be valid, including null * strings. This method is called by the {@link #setName(String)} method prior to actually setting the name. * <p> * Subclasses should override this method (as opposed to {@link #setName(String)}) if they require more control over whether * names are considered valid. * </p> * * @param potentialName the name that is to be considered * @return true if the name is considered valid, or false otherwise. * @since 3.1 */ protected boolean isValidName( final String potentialName ) { return true; } /** * Method to define the activity to be performed when this container is successfully transitioning to the STOPPED state. Only * if this method succeeds with the current state be changed to STOPPED. * * @throws ModelerCoreException * @since 3.1 */ protected void performShutdown() { } /** * Sets the eventBroker. Note that this method does not migrate or copy the listeners on the existing broker to the * <code>eventBroker</code> * * @param eventBroker The eventBroker to set * @throws IllegalStateException if the container is currently running or is either initializing or shutting down. * @since 3.1 */ public void setChangeNotifier( final ChangeNotifier notifier ) { CoreArgCheck.isNotNull(notifier); verifySetIsAllowed(this.changeNotifier); this.changeNotifier = notifier; } /** * Sets the name of the container * * @param name The name for the container * @throws IllegalArgumentException if the name is not valid * @throws IllegalStateException if the container is currently running or is either initializing or shutting down. * @since 3.1 */ @Override public void setName( final String newName ) { verifySetIsAllowed(this.name); if (!isValidName(newName)) { throw new IllegalArgumentException( ModelerCore.Util.getString("ContainerImpl.The_name___2") + newName + ModelerCore.Util.getString("ContainerImpl.__is_not_valid_3")); //$NON-NLS-1$ //$NON-NLS-2$ } final String oldName = this.name; this.name = newName; propertyChangeSupport.firePropertyChange(CONTAINER_NAME_PROPERTY, oldName, newName); } /** * Sets the runnable state. * * @since 3.1 */ protected void setState( final int state ) { this.state.setState(state); } /** * Shutdown the currently running container. In general, subclasses should not override this method because it checks the * current state to determine whether it can be shut down. If the container can be shutdown, then this method calls the * {@link #performShutdown()} method, which is generally the method that should be overridden by subclasses. * * @see Container#shutdown() * @since 3.1 */ @Override public final void shutdown() { if (this.state.isState(STOPPED)) { return; // do nothing } this.state.setState(STOPPING); performShutdown(); this.state.setState(STOPPED); } /** * Start the currently unstarted container. In general, subclasses should not override this method because it checks the * current state to determine whether it can be shut down. If the container can be shutdown, then this method calls the * {@link #performStart()} method, which is generally the method that should be overridden by subclasses. * * @see Container#start() * @since 3.1 */ @Override public final void start() { if (this.state.isState(STARTED)) { return; // do nothing } this.state.setState(STARTING); performStart(); this.state.setState(STARTED); } /** * @see java.lang.Object#toString() * @since 3.1 */ @Override public String toString() { return getName(); } /** * Verifies that a set opertion is allowed, meaning that either the property to be set is currently null or the current * runnable state is not {@link #STARTING}, {@link #STARTED}, or {@link #STOPPING}. * * @param property The property that will be set. * @throws IllegalStateException If the property to be set is not null and the current state is one of the aforementioned * values. * @since 3.1 */ protected void verifySetIsAllowed( final Object property ) { if (property != null) { if (this.state.isInTransition()) { throw new IllegalStateException( ModelerCore.Util.getString("ContainerImpl.Unable_to_set_the_name_while_the_container_is_in_transition_4")); //$NON-NLS-1$ } if (this.state.isRunning()) { throw new IllegalStateException( ModelerCore.Util.getString("ContainerImpl.Unable_to_set_the_name_on_a_running_container_5")); //$NON-NLS-1$ } } } /** * Get the name of the Container. * * @return the Container's name. * @see Container#getName() * @since 3.1 */ @Override public String getName() { return this.name; } /** * Returns the state. * * @return int * @since 3.1 */ protected int getState() { return state.getState(); } /** * This method sets the state of the AbstractContainer to {@link #UNSTARTED}. * * @since 3.1 */ protected void initializeDefaults() { this.state = new RunnableState(); } @Override public ObjectManager getObjectManager() { return this.objectManager; } /** * Create default implementation of the finder. */ protected EObjectFinder createDefaultEObjectFinder() { return new DefaultEObjectFinder(this); } /** * Create default implementation of the resource finder. */ protected ResourceFinder createDefaultResourceFinder() { return new DefaultResourceFinder(this); } protected EditingDomain createDefaultEditingDomain() { // Retrieve the adapter factory that yields item providers. final ComposedAdapterFactory adapterFactory = (ComposedAdapterFactory)ModelerCore.getMetamodelRegistry().getAdapterFactory(); CoreArgCheck.isNotNull(this.getEmfTransactionProvider()); // Create the command stack final BasicCommandStack commandStack = new BasicCommandStack(); // Create the editing domain return new ContainerEditingDomain(adapterFactory, commandStack, this); } /** * Called lazily by {@link #getEventBroker()} to create a {@link SyncEventBroker} if an EventBroker has not previously been * set. * * @since 3.1 */ protected ChangeNotifier createDefaultChangeNotifier() { return new ChangeNotifier(); } /** * Returns the EventBroker for the container. If none exists, one is created via {@link #createDefaultEventBroker()}. * * @return The container's EventBroker * @since 3.1 */ @Override public ChangeNotifier getChangeNotifier() { if (this.changeNotifier == null) { setChangeNotifier(createDefaultChangeNotifier()); } return this.changeNotifier; } /** * @see Container#getEObjectFinder() * @since 3.1 */ @Override public EObjectFinder getEObjectFinder() { if (this.finder == null) { setEObjectFinder(createDefaultEObjectFinder()); } return this.finder; } /** * @see org.teiid.designer.core.container.Container#getResourceFinder() * @since 4.2 */ @Override public ResourceFinder getResourceFinder() { if (this.resourceFinder == null) { setResourceFinder(createDefaultResourceFinder()); } return this.resourceFinder; } /** * @see org.teiid.designer.core.container.Container#setEObjectFinder(org.teiid.designer.core.container.EObjectFinder) * @since 4.3 */ @Override public void setEObjectFinder( EObjectFinder finder ) { CoreArgCheck.isNotNull(finder); verifySetIsAllowed(this.finder); this.finder = finder; } /** * @see org.teiid.designer.core.container.Container#setResourceFinder(org.teiid.designer.core.container.ResourceFinder) * @since 4.3 */ @Override public void setResourceFinder( ResourceFinder finder ) { CoreArgCheck.isNotNull(finder); verifySetIsAllowed(this.resourceFinder); this.resourceFinder = finder; } /** * Returns the emfTransactionProvider. * * @return UnitOfWorkProvider */ @Override public UnitOfWorkProvider getEmfTransactionProvider() { if (!isStarted()) { throw new ModelerCoreRuntimeException( ModelerCore.Util.getString("ContainerImpl.Container_must_be_started_prior_to_use_7")); //$NON-NLS-1$ } return emfTransactionProvider; } /** * Sets the emfTransactionProvider. * * @param emfTransactionProvider The emfTransactionProvider to set */ protected void setEmfTransactionProvider( UnitOfWorkProvider emfTransactionProvider ) { if (emfTransactionProvider == null) { CoreArgCheck.isNotNull(emfTransactionProvider, ModelerCore.Util.getString("ContainerImpl.The_UnitOfWorkProvider_may_not_be_null_8")); //$NON-NLS-1$ } this.emfTransactionProvider = emfTransactionProvider; } /** * Sets the EditingDomain. * * @param editingDomain The EditingDomain to set */ protected void setEditingDomain( final EditingDomain editingDomain ) { if (editingDomain == null) { CoreArgCheck.isNotNull(editingDomain, ModelerCore.Util.getString("ContainerImpl.The_EditingDomain_reference_may_not_be_null_1")); //$NON-NLS-1$ } this.editingDomain = editingDomain; } /** * Returns the resourceSet. * * @return ResourceSet */ @Override public final ResourceSet getResourceSet() { if (!isStarted()) { throw new ModelerCoreRuntimeException( ModelerCore.Util.getString("ContainerImpl.Container_must_be_started_prior_to_use_9")); //$NON-NLS-1$ } return this.resourceSet; } /** * Returns the metamodelRegistry. * * @return MetamodelRegistry */ @Override public MetamodelRegistry getMetamodelRegistry() { if (!isStarted()) { throw new ModelerCoreRuntimeException( ModelerCore.Util.getString("ContainerImpl.Container_must_be_started_prior_to_use_10")); //$NON-NLS-1$ } return this.metamodelRegistry; } /** * Sets the metamodelRegistry. * * @param metamodelRegistry The metamodelRegistry to set */ @Override public void setMetamodelRegistry( MetamodelRegistry metamodelRegistry ) { if (metamodelRegistry == null) { CoreArgCheck.isNotNull(metamodelRegistry, ModelerCore.Util.getString("ContainerImpl.The_reference_to_the_MetamodelRegistry_may_not_be_null_11")); //$NON-NLS-1$ } this.metamodelRegistry = metamodelRegistry; } /** * @see org.teiid.designer.core.container.Container#getDatatypeManager() * @since 4.2 */ @Override public DatatypeManager getDatatypeManager() { if (datatypeManager == null) { datatypeManager = ModelerCore.getBuiltInTypesManager(); } return datatypeManager; } public void setDatatypeManager( final DatatypeManager datatypeManager ) { CoreArgCheck.isNotNull(datatypeManager); this.datatypeManager = datatypeManager; } // ################################################################################### // # Public ResourceSet methods (that mostly just delegate to the contained instance) // ################################################################################### /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.ecore.resource.ResourceSet#createResource(org.eclipse.emf.common.util.URI) */ @Override public Resource createResource( final URI uri ) { return this.resourceSet.createResource(uri); } /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.ecore.resource.ResourceSet#getAdapterFactories() */ @Override public EList<AdapterFactory> getAdapterFactories() { return this.resourceSet.getAdapterFactories(); } /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.ecore.resource.ResourceSet#getAllContents() */ @Override public TreeIterator<Notifier> getAllContents() { return this.resourceSet.getAllContents(); } /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.ecore.resource.ResourceSet#getEObject(org.eclipse.emf.common.util.URI, boolean) */ @Override public EObject getEObject( final URI uri, final boolean loadOnDemand ) { EObject result = null; // If the URI contains a UUID fragement ... if (uri != null && uri.fragment() != null) { String uriFragment = uri.fragment(); URI resourceUri = uri.trimFragment(); int beginIndex = uriFragment.indexOf(UUID.PROTOCOL); if (beginIndex != -1) { beginIndex = beginIndex + UUID.PROTOCOL.length() + 1; if (beginIndex < uriFragment.length()) { String uuidStringWithoutProtocol = uriFragment.substring(beginIndex); try { ObjectID uuid = UUID.stringToObject(uuidStringWithoutProtocol); result = (EObject)getEObjectFinder().find(uuid); if (result == null) { result = getEObjectFromExternalResourceSets(uri, false); } // If we have found a result for this UUID then check that it's resource is // the same as referenced in the URI. If it is not, then we found the EObject // in one of the external resource sets when it instead should have resolved to a // resource in the workspace. if (result != null) { Resource resource = this.resourceSet.getResource(resourceUri, false); Resource resultantResource = result.eResource(); if (resource != null && !resource.equals(resultantResource)) { result = null; } } } catch (InvalidIDException e) { ModelerCore.Util.log(IStatus.ERROR, e, e.getMessage()); } } } } if (result != null) { return result; } // Try resolving in the Container's resource set ... return this.resourceSet.getEObject(uri, loadOnDemand); } private EObject getEObjectFromExternalResourceSets( final URI uri, final boolean loadOnDemand ) { EObject result = null; if (this.resourceSet instanceof EmfResourceSetImpl) { final ResourceSet[] externalResourceSets = ((EmfResourceSetImpl)this.resourceSet).getExternalResourceSets(); for (int i = 0; i != externalResourceSets.length; ++i) { ResourceSet rsrcSet = externalResourceSets[i]; result = rsrcSet.getEObject(uri, loadOnDemand); if (result != null) { break; } } } return result; } /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.ecore.resource.ResourceSet#getLoadOptions() */ @Override public Map<Object, Object> getLoadOptions() { return this.resourceSet.getLoadOptions(); } /** * @see org.eclipse.emf.ecore.resource.ResourceSet#getPackageRegistry() * @since 4.3 */ @Override public org.eclipse.emf.ecore.EPackage.Registry getPackageRegistry() { return this.resourceSet.getPackageRegistry(); } /** * @see org.eclipse.emf.ecore.resource.ResourceSet#setPackageRegistry(org.eclipse.emf.ecore.EPackage.Registry) * @since 4.3 */ @Override public void setPackageRegistry( org.eclipse.emf.ecore.EPackage.Registry packageRegistry ) { this.resourceSet.setPackageRegistry(packageRegistry); } /** * Loads the resource at the given URI. The created resource loads the model objects into the ObjectManager as well. * * @param the URI for the resource to be loaded. * @return ResourceSetImpl * @throws ModelerCoreException */ @Override public Resource getResource( final URI uri, final boolean loadOnDemand ) { if (uri == null) { CoreArgCheck.isNotNull(uri, ModelerCore.Util.getString("ContainerImpl.The_URI_to_load_may_not_be_null_12")); //$NON-NLS-1$ } if (!isStarted()) { throw new ModelerCoreRuntimeException( ModelerCore.Util.getString("ContainerImpl.Container_must_be_started_prior_to_use_13")); //$NON-NLS-1$ } // Get txn final UnitOfWork txn = getEmfTransactionProvider().getCurrent(); boolean startedTxn = false; if (!txn.isStarted()) { try { txn.begin(); } catch (ModelerCoreException e) { ModelerCore.Util.log(IStatus.ERROR, e, e.getMessage()); } startedTxn = true; } Resource resource = null; boolean created = false; try { // See if the MetamodelRegistry has the URI ... log(ModelerCore.Util.getString("ContainerImpl.>>_ContainerImpl.delegatedGetResource__URI___14") + uri + ", loadOnDemand= " + loadOnDemand); //$NON-NLS-1$ //$NON-NLS-2$ if (this.metamodelRegistry != null && this.metamodelRegistry.containsURI(uri)) { resource = this.metamodelRegistry.getResource(uri); log(ModelerCore.Util.getString("ContainerImpl.>>_Returning_Resource_in_the_MetamodelRegistry_with_URI___16") + uri + "\""); //$NON-NLS-1$ //$NON-NLS-2$ } // Otherwsise, just delegate to the model resource set ... created = this.resourceSet.getResource(uri, false) == null; resource = this.resourceSet.getResource(uri, loadOnDemand); } finally { if (startedTxn) { try { if (resource != null) { txn.commit(); } else { txn.rollback(); } } catch (ModelerCoreException e) { throw new ModelerCoreRuntimeException(e); } } // We just read in the file; make sure it does NOT think it has changes. // When root objects are created and added to the Resource.getContents() list, the // list may mark the resource as changed. if (resource != null && created) { resource.setModified(false); } } return resource; } /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.ecore.resource.ResourceSet#getResourceFactoryRegistry() */ @Override public Registry getResourceFactoryRegistry() { return this.resourceSet.getResourceFactoryRegistry(); } /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.ecore.resource.ResourceSet#getResources() */ @Override public EList<Resource> getResources() { return this.resourceSet.getResources(); } /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.ecore.resource.ResourceSet#getURIConverter() */ @Override public URIConverter getURIConverter() { return this.resourceSet.getURIConverter(); } /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.ecore.resource.ResourceSet#setResourceFactoryRegistry(org.eclipse.emf.ecore.resource.Resource.Factory.Registry) */ @Override public void setResourceFactoryRegistry( final Registry resourceFactoryRegistry ) { this.resourceSet.setResourceFactoryRegistry(resourceFactoryRegistry); } /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.ecore.resource.ResourceSet#setURIConverter(org.eclipse.emf.ecore.resource.URIConverter) */ @Override public void setURIConverter( final URIConverter converter ) { this.resourceSet.setURIConverter(converter); } /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.common.notify.Notifier#eAdapters() */ @Override public EList<Adapter> eAdapters() { return this.resourceSet.eAdapters(); } /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.common.notify.Notifier#eDeliver() */ @Override public boolean eDeliver() { return this.resourceSet.eDeliver(); } /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.common.notify.Notifier#eNotify(org.eclipse.emf.common.notify.Notification) */ @Override public void eNotify( final Notification notification ) { this.resourceSet.eNotify(notification); } /** * This implementation forwards the request directly to the contained ResourceSet. * * @see org.eclipse.emf.common.notify.Notifier#eSetDeliver(boolean) */ @Override public void eSetDeliver( final boolean deliver ) { this.resourceSet.eSetDeliver(deliver); } // ################################################################################### // # Public IEditingDomainProvider methods // ################################################################################### /* (non-Javadoc) * @see org.eclipse.emf.edit.domain.IEditingDomainProvider#getEditingDomain() */ @Override public EditingDomain getEditingDomain() { if (this.editingDomain == null) { this.setEditingDomain(createDefaultEditingDomain()); } return this.editingDomain; } // ################################################################################### // # Protected methods // ################################################################################### /** * Indicates if the specified <code>Notification</code>'s resource should be set modified. * * @param notification the notification being checked * @return <code>true</code> if it should be processed; <code>false</code> otherwise. */ private boolean shouldProcess( Notification notification ) { // don't process schema referencing directives as this will set dependent resources dirty if (notification.getNotifier() != null && notification.getFeatureID(notification.getNotifier().getClass()) == XSDPackage.XSD_SCHEMA__REFERENCING_DIRECTIVES) { return false; } Object val; switch (notification.getEventType()) { case Notification.ADD: case Notification.ADD_MANY: { val = notification.getNewValue(); break; } case Notification.REMOVE: case Notification.REMOVE_MANY: { val = notification.getOldValue(); break; } case Notification.RESOLVE: { return false; } case Notification.SET: case Notification.UNSET: { // only process if value has changed boolean result = true; Object oldValue = notification.getOldValue(); Object newValue = notification.getNewValue(); if (oldValue == null) { result = (newValue != null); } else if (newValue != null) { result = !oldValue.equals(newValue); } return result; } default: { return true; } } // don't process if collections go from null to empty if (val == null || (val instanceof Collection && ((Collection)val).isEmpty()) || (val instanceof Object[] && ((Object[])val).length == 0)) { return false; } return true; } /** * Indicates if the specified <code>Resource</codee> is a member of an external resource set. * * @param theResource the resource being checked * @return <code>true</code> if a member; <code>false</code> otherwise. * @since 5.0.2 */ private boolean isExternalResourceSetMember( Resource theResource ) { return ModelerCore.isResourceInExternalResourceSet(theResource); } protected void processNotification( Notification notification ) { if (!shouldProcess(notification)) { return; } Resource resource = null; Object notifier = notification.getNotifier(); int eventType = notification.getEventType(); boolean doit = false; // mark the resource modified if the notification is for (1) a resource that is not a member of // an external resource set or for (2) an EObject of a resource. if (notifier instanceof Resource) { // make sure the feature is NOT the modified feature resource = (Resource)notifier; int featureId = notification.getFeatureID(resource.getClass()); if (eventType != Notification.REMOVING_ADAPTER && featureId != Resource.RESOURCE__IS_LOADED && featureId != Resource.RESOURCE__IS_MODIFIED && featureId != Resource.RESOURCE__RESOURCE_SET && !isExternalResourceSetMember(resource)) { doit = true; } } else if (notifier instanceof EObject) { resource = ((EObject)notifier).eResource(); doit = true; } // Ensure change occurs within a transaction (potentially after the fact) Object feature = notification.getFeature(); Object newVal = notification.getNewValue(); String desc = (feature == null ? null : ModelerCore.Util.getString("ContainerImpl.setFeatureDescription", feature, newVal)); //$NON-NLS-1$ boolean xActionStarted = ModelerCore.startTxn(desc, this); boolean xActionSucceeded = false; try { try { Container ctnr = ModelerCore.getModelContainer(); if (xActionStarted && CoreModelerPlugin.getTransactionManager() != null && feature != null && eventType == Notification.SET && ctnr != null && notifier instanceof EObject && (!(resource instanceof XResource) || !((XResource)resource).isLoading())) { CommandParameter prm = new CommandParameter(notifier, feature, newVal); Command cmd = ((ContainerImpl)ctnr).getEditingDomain().createCommand(SetCommand.class, prm); ((ModelEditorImpl)ModelerCore.getModelEditor()).postExecuteCommand((EObject)notifier, cmd); } } catch (CoreException err) { ModelerCore.Util.log(err); } final UnitOfWorkImpl txn = (UnitOfWorkImpl)getEmfTransactionProvider().getCurrent(); boolean shouldCheckImports = false; if (resource != null) { if (resource instanceof XResource) { XResource xRes = (XResource)resource; shouldCheckImports = !xRes.isLoading() && !xRes.isUnloading(); } else { shouldCheckImports = true; } if (shouldCheckImports) { ProcessedNotificationResult result = ExternalResourceImportsHelper.processNotification(notification); if (result != null && !result.getDereferencedResources().isEmpty()) { txn.addProcessedNotificationResult(result); } } } //debug("Change", resource, theNotification); //$NON-NLS-1$ // now mark as modified if it is (1) not already modified or if (2) we're not rolling back a transaction if (doit && (resource != null) && !resource.isModified() && !txn.isRollingBack()) { resource.setModified(true); } try { if (txn.isStarted() || txn.isRollingBack()) { // now let the transaction fire the events to the workspace txn.processNotification(notification); } else { notifyForClosedUoW(txn, notification); } } catch (ModelerCoreException e) { ModelerCore.Util.log(e); } // Mark transaction as succeeded so it gets committed xActionSucceeded = true; } finally { if (xActionStarted) { if (xActionSucceeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } public static void debug( String heading, Notification notification ) { System.out.println("\n" + heading + ":"); //$NON-NLS-1$ //$NON-NLS-2$ Resource resource = null; Object notifier = notification.getNotifier(); if (notifier instanceof Resource) { // make sure the feature is NOT the modified feature resource = (Resource)notifier; } else if (notifier instanceof EObject) { resource = ((EObject)notifier).eResource(); } System.out.println("\tResource=" + resource); //$NON-NLS-1$ System.out.println("\tNotifier=" + notifier); //$NON-NLS-1$ System.out.print("\tType="); //$NON-NLS-1$ switch (notification.getEventType()) { case Notification.ADD: System.out.println("ADD");break; //$NON-NLS-1$ case Notification.ADD_MANY: System.out.println("ADD_MANY");break; //$NON-NLS-1$ case Notification.MOVE: System.out.println("MOVE");break; //$NON-NLS-1$ case Notification.REMOVE: System.out.println("REMOVE");break; //$NON-NLS-1$ case Notification.REMOVE_MANY: System.out.println("REMOVE_MANY");break; //$NON-NLS-1$ case Notification.REMOVING_ADAPTER: System.out.println("REMOVING_ADAPTER");break; //$NON-NLS-1$ case Notification.RESOLVE: System.out.println("RESOLVE");break; //$NON-NLS-1$ case Notification.SET: System.out.println("SET");break; //$NON-NLS-1$ case Notification.UNSET: System.out.println("UNSET");break; //$NON-NLS-1$ } int featureId = notification.getFeatureID(notification.getNotifier().getClass()); System.out.println("\tFeature ID=" + featureId); //$NON-NLS-1$ if (notifier instanceof ResourceSet) { System.out.println("\tFeature=RESOURCES"); //$NON-NLS-1$ } else if (notifier instanceof Resource) { System.out.print("\tFeature="); //$NON-NLS-1$ switch (featureId) { case Resource.RESOURCE__CONTENTS: System.out.println("CONTENTS");break; //$NON-NLS-1$ case Resource.RESOURCE__ERRORS: System.out.println("ERRORS");break; //$NON-NLS-1$ case Resource.RESOURCE__IS_LOADED: System.out.println("IS_LOADED");break; //$NON-NLS-1$ case Resource.RESOURCE__IS_MODIFIED: System.out.println("IS_MODIFIED");break; //$NON-NLS-1$ case Resource.RESOURCE__IS_TRACKING_MODIFICATION: System.out.println("IS_TRACKING_MODIFICATION");break; //$NON-NLS-1$ case Resource.RESOURCE__RESOURCE_SET: System.out.println("RESOURCE_SET");break; //$NON-NLS-1$ case Resource.RESOURCE__URI: System.out.println("URI");break; //$NON-NLS-1$ case Resource.RESOURCE__WARNINGS: System.out.println("WARNINGS");break; //$NON-NLS-1$ } } else { System.out.println("\tFeature=" + notification.getFeature()); //$NON-NLS-1$ } System.out.println("\tNew Value=" + notification.getNewValue()); //$NON-NLS-1$ System.out.println("\tOld Value=" + notification.getOldValue()); //$NON-NLS-1$ } /** * If there is no currently started uow check to see if we are dealing with non-proxied metamodel objects. If so, start the * uow, process the notification and commit the uow. */ private void notifyForClosedUoW( final UnitOfWorkImpl txn, final Notification msg ) { final Object notifier = msg.getNotifier(); if (notifier instanceof EObject) { final String nsUriString = ((EObject)notifier).eClass().getEPackage().getNsURI(); if (!CoreStringUtil.isEmpty(nsUriString)) { final MetamodelDescriptor descriptor = ModelerCore.getMetamodelRegistry().getMetamodelDescriptor(nsUriString); if (descriptor != null) { try { txn.begin(); txn.setSource(this); // Set the container as the source of this transaction txn.processNotification(msg); return; } catch (ModelerCoreException e) { ModelerCore.Util.log(IStatus.ERROR, e, e.getMessage()); } finally { if (txn.isStarted()) { try { txn.commit(); } catch (ModelerCoreException e1) { ModelerCore.Util.log(IStatus.ERROR, e1, e1.getMessage()); } } } } } } if (ModelerCore.DEBUG_NOTIFICATIONS) { ModelerCore.Util.log(IStatus.INFO, ModelerCore.Util.getString("ContainerImpl.Could_not_process_notification_for_closed_txn_1")); //$NON-NLS-1$ } } /** * @see AbstractContainer#performStart() */ protected void performStart() { setState(STARTING); // Create the resource set and add the EContentAdapter for processing notifications this.resourceSet = new EmfResourceSetImpl(this); this.resourceSet.eAdapters().add(new EContentAdapter() { @Override public void notifyChanged( Notification msg ) { super.notifyChanged(msg); processNotification(msg); } }); // Set the URIConverter instance ... resourceSet.setURIConverter(new ExtensibleURIConverterImpl()); // Create the EMF Transaction Provider this.emfTransactionProvider = new UnitOfWorkProviderImpl(this.resourceSet); // Set the Metamodel Registry reference MetamodelRegistry registry = ModelerCore.getMetamodelRegistry(); this.metamodelRegistry = registry; setState(STARTED); } protected boolean isReadOnly( final Resource resource ) { if (resource != null && resource.getURI().isFile()) { File f = new File(resource.getURI().toFileString()); if (f.exists() && !f.canWrite()) { return true; } } return false; } // public void testNonPlatformLogIStatus_ErrorMultiStatusWithMessageWithThrowable() { // final int embeddedSeverity1 = IStatus.WARNING; // final int embeddedSeverity2 = IStatus.ERROR; // final int code = 100; // final String embeddedMessage1 = "This is the embedded warning message 1"; //$NON-NLS-1$ // final String embeddedMessage2 = "This is the embedded error message 2"; //$NON-NLS-1$ // final String message = "This is the message for the outter multistatus"; //$NON-NLS-1$ // final Throwable t = new Throwable("This is the throwable"); //$NON-NLS-1$ // t.fillInStackTrace(); // final String pluginID = "my.plugin.id"; //$NON-NLS-1$ // final IStatus embeddedStatus1 = new Status(embeddedSeverity1,pluginID,code+1,embeddedMessage1,t); // final IStatus embeddedStatus2 = new Status(embeddedSeverity2,pluginID,code,embeddedMessage2,t); // final IStatus[] embedded = new IStatus[]{embeddedStatus1,embeddedStatus2}; // final IStatus status = new MultiStatus(pluginID,code,embedded,message,t); // CoreModelerPlugin.Util.log(status); // } // ############################################################################# // # Private methods // ############################################################################# // private void tempInitializeMetamodelRegistry(){ // String METAMODELS_EXTENSION_POINT_ID = "com.metamatrix.mtk.emf.metamodel"; // this.metamodelRegistry = new MetamodelRegistryImpl(); // // // Load the MetamodelRegistry will all extensions of the metamodel extension point // final IExtension[] extensions = PluginUtilities.getExtensions(METAMODELS_EXTENSION_POINT_ID); // for (int i = 0; i < extensions.length; i++) { // final IExtension extension = extensions[i]; // try { // metamodelRegistry.register(new MetamodelDescriptorImpl(extension)); // } catch (ModelerCoreException e) { // System.err.println(e); // } // } // } private void log( final String msg ) { if (ModelerCore.DEBUG) { ModelerCore.Util.log(msg); } } /** * Returns the IStatus. * * @return Istatus */ public IStatus getStatus() { return this.status; } /** * @see org.teiid.designer.core.container.Container#addResourceDescriptor(org.teiid.designer.core.container.ResourceDescriptor) */ @Override public void addResourceDescriptor( ResourceDescriptor resourceDescriptor ) throws ModelerCoreException { ResourceDescriptorImpl.register(resourceDescriptor, resourceSet); } /** * @see org.teiid.designer.core.container.Container#addExternalResourceSet(org.eclipse.emf.ecore.resource.ResourceSet) */ @Override public void addExternalResourceSet( final ResourceSet rsrcSet ) { CoreArgCheck.isNotNull(rsrcSet); if (this.resourceSet instanceof EmfResourceSetImpl) { ((EmfResourceSetImpl)this.resourceSet).addExternalResourceSet(rsrcSet); } } /** * @see org.teiid.designer.core.container.Container#getExternalResourceSets() * @since 4.3 */ @Override public ResourceSet[] getExternalResourceSets() { if (this.resourceSet instanceof EmfResourceSetImpl) { return ((EmfResourceSetImpl)this.resourceSet).getExternalResourceSets(); } return EMPTY_RESOURCE_SET_ARRAY; } /** * @see org.teiid.designer.core.container.Container#getOptions() * @since 4.3 */ @Override public Map getOptions() { return (this.options == null ? Collections.EMPTY_MAP : this.options); } /** * @see org.teiid.designer.core.container.Container#setOptions(java.util.Map) * @since 4.3 */ @Override public void setOptions( Map options ) { verifySetIsAllowed(this.options); this.options = options; } /** * {@inheritDoc} * * @see org.eclipse.emf.ecore.resource.ResourceSet#createResource(org.eclipse.emf.common.util.URI, java.lang.String) */ @Override public Resource createResource( URI uri, String contentType ) { return this.resourceSet.createResource(uri, contentType); } }