blob: a3b2e63ce41e65f5f95a723dc2367663544a8dd6 [file] [log] [blame]
/***************************************************************************
* Copyright (c) 2004 - 2008 Eike Stepper, Germany.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
* Simon McDuff - http://bugs.eclipse.org/226778
* Simon McDuff - http://bugs.eclipse.org/213402
* Simon McDuff - http://bugs.eclipse.org/246705
**************************************************************************/
package org.eclipse.emf.cdo.eresource.impl;
import org.eclipse.emf.cdo.CDOState;
import org.eclipse.emf.cdo.CDOTransaction;
import org.eclipse.emf.cdo.CDOView;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.eresource.CDOResource;
import org.eclipse.emf.cdo.eresource.EresourcePackage;
import org.eclipse.emf.cdo.util.CDOURIUtil;
import org.eclipse.emf.cdo.util.ObjectNotFoundException;
import org.eclipse.emf.internal.cdo.CDOStateMachine;
import org.eclipse.emf.internal.cdo.CDOTransactionImpl;
import org.eclipse.emf.internal.cdo.CDOViewImpl;
import org.eclipse.emf.internal.cdo.InternalCDOObject;
import org.eclipse.emf.internal.cdo.util.FSMUtil;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.notify.impl.NotificationChainImpl;
import org.eclipse.emf.common.notify.impl.NotificationImpl;
import org.eclipse.emf.common.notify.impl.NotifyingListImpl;
import org.eclipse.emf.common.util.AbstractTreeIterator;
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.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
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.resource.impl.ResourceImpl;
import org.eclipse.emf.ecore.util.InternalEList;
import org.eclipse.emf.ecore.util.NotifyingInternalEListImpl;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
/**
* <!-- begin-user-doc --> An implementation of the model object '<em><b>CDO Resource</b></em>'.
*
* @extends Resource.Internal<!-- end-user-doc -->
* <p>
* The following features are implemented:
* <ul>
* <li>{@link org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl#getResourceSet <em>Resource Set</em>}</li>
* <li>{@link org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl#getURI <em>URI</em>}</li>
* <li>{@link org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl#getContents <em>Contents</em>}</li>
* <li>{@link org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl#isModified <em>Modified</em>}</li>
* <li>{@link org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl#isLoaded <em>Loaded</em>}</li>
* <li>{@link org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl#isTrackingModification <em>Tracking
* Modification</em>}</li>
* <li>{@link org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl#getErrors <em>Errors</em>}</li>
* <li>{@link org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl#getWarnings <em>Warnings</em>}</li>
* <li>{@link org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl#getTimeStamp <em>Time Stamp</em>}</li>
* </ul>
* </p>
* @generated
*/
public class CDOResourceImpl extends CDOResourceNodeImpl implements CDOResource, Resource.Internal
{
/**
* The default URI converter when there is no resource set.
*
* @ADDED
*/
private static URIConverter defaultURIConverter;
/**
* @ADDED
*/
private boolean root;
/**
* @ADDED
*/
private URI initialURI;
/**
* @ADDED
*/
private boolean existing;
/**
* @ADDED
*/
private boolean loading;
/**
* @ADDED
*/
private boolean loaded;
/**
* @ADDED
*/
private EList<Diagnostic> errors;
/**
* @ADDED
*/
private EList<Diagnostic> warnings;
/**
* @ADDED
* @since 2.0
*/
public CDOResourceImpl(URI initialURI)
{
this.initialURI = initialURI;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
protected CDOResourceImpl()
{
super();
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
protected EClass eStaticClass()
{
return EresourcePackage.Literals.CDO_RESOURCE;
}
/**
* @since 2.0
*/
public boolean isRoot()
{
return root;
}
void setRoot(boolean root)
{
this.root = root;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public ResourceSet getResourceSet()
{
return (ResourceSet)eGet(EresourcePackage.Literals.CDO_RESOURCE__RESOURCE_SET, true);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public void setResourceSet(ResourceSet newResourceSet)
{
eSet(EresourcePackage.Literals.CDO_RESOURCE__RESOURCE_SET, newResourceSet);
}
/**
* <!-- begin-user-doc -->
*
* @since 2.0 <!-- end-user-doc -->
* @generated
*/
public URI getURIGen()
{
return (URI)eGet(EresourcePackage.Literals.CDO_RESOURCE__URI, true);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
public URI getURI()
{
if (cdoID() == null && initialURI != null)
{
return initialURI;
}
return CDOURIUtil.createResourceURI(cdoView(), getPath());
}
/**
* <!-- begin-user-doc -->
*
* @since 2.0 <!-- end-user-doc -->
* @generated
*/
public void setURIGen(URI newURI)
{
eSet(EresourcePackage.Literals.CDO_RESOURCE__URI, newURI);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
public void setURI(URI newURI)
{
String newPath = CDOURIUtil.extractResourcePath(newURI);
setPath(newPath);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
@SuppressWarnings("unchecked")
public EList<EObject> getContents()
{
if (FSMUtil.isTransient(this))
{
EList<EObject> transientContents = (EList<EObject>)eSettings[EresourcePackage.CDO_RESOURCE__CONTENTS];
if (transientContents == null)
{
transientContents = new TransientContents<EObject>();
eSettings[EresourcePackage.CDO_RESOURCE__CONTENTS] = transientContents;
// throw new ImplementationError();
}
return transientContents;
}
return (EList<EObject>)eGet(EresourcePackage.Literals.CDO_RESOURCE__CONTENTS, true);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
* @since 2.0
*/
@Override
public void cdoInternalPostInvalid()
{
super.cdoInternalPostInvalid();
existing = false;
cdoView().getResourceSet().getResources().remove(this);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public boolean isModified()
{
return ((Boolean)eGet(EresourcePackage.Literals.CDO_RESOURCE__MODIFIED, true)).booleanValue();
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public void setModified(boolean newModified)
{
eSet(EresourcePackage.Literals.CDO_RESOURCE__MODIFIED, new Boolean(newModified));
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
public boolean isLoaded()
{
return loaded;
}
/**
* @see ResourceImpl#setLoaded(boolean)
* @ADDED
*/
private Notification setLoaded(boolean isLoaded)
{
boolean oldIsLoaded = loaded;
loaded = isLoaded;
if (eNotificationRequired())
{
Notification notification = new NotificationImpl(Notification.SET, oldIsLoaded, isLoaded)
{
@Override
public Object getNotifier()
{
return CDOResourceImpl.this;
}
@Override
public int getFeatureID(Class<?> expectedClass)
{
return EresourcePackage.CDO_RESOURCE__LOADED;
}
};
return notification;
}
else
{
return null;
}
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public boolean isTrackingModification()
{
return ((Boolean)eGet(EresourcePackage.Literals.CDO_RESOURCE__TRACKING_MODIFICATION, true)).booleanValue();
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public void setTrackingModification(boolean newTrackingModification)
{
eSet(EresourcePackage.Literals.CDO_RESOURCE__TRACKING_MODIFICATION, new Boolean(newTrackingModification));
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
public EList<Diagnostic> getErrors()
{
if (errors == null)
{
errors = new NotifyingListImpl<Diagnostic>()
{
private static final long serialVersionUID = 1L;
@Override
protected boolean isNotificationRequired()
{
return CDOResourceImpl.this.eNotificationRequired();
}
@Override
public Object getNotifier()
{
return CDOResourceImpl.this;
}
@Override
public int getFeatureID()
{
return EresourcePackage.CDO_RESOURCE__ERRORS;
}
};
}
return errors;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
public EList<Diagnostic> getWarnings()
{
if (warnings == null)
{
warnings = new NotifyingListImpl<Diagnostic>()
{
private static final long serialVersionUID = 1L;
@Override
protected boolean isNotificationRequired()
{
return CDOResourceImpl.this.eNotificationRequired();
}
@Override
public Object getNotifier()
{
return CDOResourceImpl.this;
}
@Override
public int getFeatureID()
{
return EresourcePackage.CDO_RESOURCE__WARNINGS;
}
};
}
return warnings;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public long getTimeStamp()
{
return ((Long)eGet(EresourcePackage.Literals.CDO_RESOURCE__TIME_STAMP, true)).longValue();
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public void setTimeStamp(long newTimeStamp)
{
eSet(EresourcePackage.Literals.CDO_RESOURCE__TIME_STAMP, new Long(newTimeStamp));
}
/**
* @ADDED
* @see ResourceImpl#getAllContents()
*/
public TreeIterator<EObject> getAllContents()
{
return new AbstractTreeIterator<EObject>(this, false)
{
private static final long serialVersionUID = 1L;
@Override
public Iterator<EObject> getChildren(Object object)
{
return object == CDOResourceImpl.this ? CDOResourceImpl.this.getContents().iterator() : ((EObject)object)
.eContents().iterator();
}
};
}
/**
* <b>Note:</b> URI from temporary objects are going to changed when we commit the CDOTransaction. Objects will not be
* accessible from their temporary URI once CDOTransaction is committed.
* <p>
* <b>Note:</b> This resource is not actually used to lookup the resulting object in CDO. Only the CDOView is used for
* this lookup! This means that this resource can be used to resolve <em>any</em> fragment with a CDOID of the
* associated CDOView.
*
* @ADDED
*/
public EObject getEObject(String uriFragment)
{
// Should we return CDOResource (this ?) ?
if (uriFragment == null)
{
return null;
}
CDOID cdoID = CDOIDUtil.read(uriFragment, cdoView().getSession().getPackageManager().getCDOIDObjectFactory());
if (cdoID.isNull() || cdoID.isTemporary() && !cdoView().isObjectRegistered(cdoID))
{
return null;
}
if (cdoID.isObject())
{
try
{
return cdoView().getObject(cdoID, true);
}
catch (ObjectNotFoundException ex)
{
// Do nothing
// getEObject return null when the object cannot be resolved.
}
}
// If it doesn`t match to anything we return null like ResourceImpl.getEObject
return null;
}
/**
* @ADDED
*/
public String getURIFragment(EObject object)
{
// TODO if object == this ??? what we do. Is it wanted ? How we handle them ?
InternalCDOObject internalCDOObject = FSMUtil.adapt(object, cdoView());
StringBuilder builder = new StringBuilder();
CDOIDUtil.write(builder, internalCDOObject.cdoID());
return builder.toString();
}
/**
* @ADDED
*/
public void load(InputStream inputStream, Map<?, ?> options) throws IOException
{
throw new UnsupportedOperationException();
// if (inputStream instanceof CDOResourceInputStream)
// {
// CDOResourceInputStream stream = (CDOResourceInputStream)inputStream;
// URI uri = stream.getURI();
// }
// else
// {
// throw new IOException("Stream not supported: " + inputStream);
// }
}
/**
* @ADDED
*/
public void load(Map<?, ?> options) throws IOException
{
if (!isLoaded())
{
CDOViewImpl view = cdoView();
if (!FSMUtil.isTransient(this))
{
CDOID id = cdoID();
if (id == null || id != null && !view.isObjectRegistered(id))
{
try
{
view.registerProxyResource(this);
}
catch (Exception ex)
{
setExisting(false);
cdoInternalSetState(CDOState.TRANSIENT);
throw new IOWrappedException(ex);
}
}
}
setLoaded(true);
// URIConverter uriConverter = getURIConverter();
//
// // If an input stream can't be created, ensure that the resource is still considered loaded after the failure,
// // and do all the same processing we'd do if we actually were able to create a valid input stream.
// //
// InputStream inputStream = null;
//
// try
// {
// inputStream = uriConverter.createInputStream(getURI(), options);
// }
// catch (IOException exception)
// {
// Notification notification = setLoaded(true);
// loading = true;
// if (errors != null)
// {
// errors.clear();
// }
//
// if (warnings != null)
// {
// warnings.clear();
// }
//
// loading = false;
// if (notification != null)
// {
// eNotify(notification);
// }
//
// setModified(false);
// throw exception;
// }
//
// try
// {
// load(inputStream, options);
// }
// finally
// {
// inputStream.close();
// // TODO Handle timeStamp
// // Long timeStamp = (Long)response.get(URIConverter.RESPONSE_TIME_STAMP_PROPERTY);
// // if (timeStamp != null)
// // {
// // setTimeStamp(timeStamp);
// // }
// }
}
}
/**
* Returns the URI converter. This typically gets the {@link ResourceSet#getURIConverter converter} from the
* {@link #getResourceSet containing} resource set, but it calls {@link #getDefaultURIConverter} when there is no
* containing resource set.
*
* @return the URI converter.
* @ADDED
*/
private URIConverter getURIConverter()
{
return getResourceSet() == null ? getDefaultURIConverter() : getResourceSet().getURIConverter();
}
/**
* Returns the default URI converter that's used when there is no resource set.
*
* @return the default URI converter.
* @see #getURIConverter
* @ADDED
*/
private static synchronized URIConverter getDefaultURIConverter()
{
if (defaultURIConverter == null)
{
defaultURIConverter = new ExtensibleURIConverterImpl();
}
return defaultURIConverter;
}
/**
* @ADDED
*/
public void save(Map<?, ?> options) throws IOException
{
CDOView view = cdoView();
if (view instanceof CDOTransaction)
{
CDOTransaction transaction = (CDOTransaction)view;
transaction.commit();
}
else
{
throw new IOException("CDO view is read-only: " + view);
}
}
/**
* @ADDED
*/
public void save(OutputStream outputStream, Map<?, ?> options) throws IOException
{
// Do nothing
}
/**
* @ADDED
*/
public void unload()
{
// Do nothing
}
/**
* @ADDED
*/
public void delete(Map<?, ?> defaultDeleteOptions) throws IOException
{
if (FSMUtil.isTransient(this))
{
removeFromResourceSet();
}
else
{
if (isRoot())
{
throw new UnsupportedOperationException();
}
if (getFolder() == null)
{
CDOViewImpl view = cdoView();
view.getRootResource().getContents().remove(this);
}
else
{
basicSetFolder(null, false);
}
}
}
/**
* @since 2.0
*/
@Override
public void cdoInternalPostDetach()
{
super.cdoInternalPostDetach();
removeFromResourceSet();
}
private void removeFromResourceSet()
{
ResourceSet resourceSet = getResourceSet();
if (resourceSet != null)
{
resourceSet.getResources().remove(this);
}
}
/**
* @ADDED
*/
public void attached(EObject object)
{
if (!FSMUtil.isTransient(this))
{
InternalCDOObject cdoObject = FSMUtil.adapt(object, cdoView());
attached(cdoObject, cdoView().toTransaction());
}
}
/**
* @ADDED
*/
private void attached(InternalCDOObject cdoObject, CDOTransactionImpl transaction)
{
CDOStateMachine.INSTANCE.attach(cdoObject, transaction);
}
/**
* @ADDED
*/
public void detached(EObject object)
{
if (!FSMUtil.isTransient(this))
{
InternalCDOObject cdoObject = FSMUtil.adapt(object, cdoView());
CDOStateMachine.INSTANCE.detach(cdoObject);
}
}
/**
* @ADDED
* @see ResourceImpl#basicSetResourceSet(ResourceSet, NotificationChain)
*/
public NotificationChain basicSetResourceSet(ResourceSet resourceSet, NotificationChain notifications)
{
ResourceSet oldResourceSet = getResourceSet();
if (oldResourceSet != null)
{
notifications = ((InternalEList<Resource>)oldResourceSet.getResources()).basicRemove(this, notifications);
}
setResourceSet(resourceSet);
if (eNotificationRequired())
{
if (notifications == null)
{
notifications = new NotificationChainImpl(2);
}
notifications.add(new NotificationImpl(Notification.SET, oldResourceSet, resourceSet)
{
@Override
public Object getNotifier()
{
return CDOResourceImpl.this;
}
@Override
public int getFeatureID(Class<?> expectedClass)
{
return RESOURCE__RESOURCE_SET;
}
});
}
return notifications;
}
/**
* @ADDED
*/
public boolean isLoading()
{
return loading;
}
/**
* @ADDED
*/
public boolean isExisting()
{
return existing;
}
/**
* @ADDED
*/
void setExisting(boolean existing)
{
this.existing = existing;
}
/**
* @ADDED
*/
@Override
protected EList<?> createList(EStructuralFeature eStructuralFeature)
{
if (eStructuralFeature == EresourcePackage.eINSTANCE.getCDOResource_Contents())
{
return new PersistentContents(eStructuralFeature);
}
return super.createList(eStructuralFeature);
}
/**
* {@link ResourceImpl.ContentsEList}!!! --> Bugzilla!
*
* @ADDED
* @author Eike Stepper
*/
protected class PersistentContents extends CDOStoreEList<Object>
{
private static final long serialVersionUID = 1L;
@SuppressWarnings("deprecation")
public PersistentContents(EStructuralFeature eStructuralFeature)
{
super(eStructuralFeature);
if (!cdoView().hasUniqueResourceContents())
{
kind &= ~IS_UNIQUE;
}
}
/**
* Optimization taken from ResourceImpl.EContentList.contains.
*
* @since 2.0
*/
@Override
public boolean contains(Object object)
{
return size() <= 4 ? super.contains(object) : object instanceof InternalEObject
&& ((InternalEObject)object).eDirectResource() == CDOResourceImpl.this;
}
/**
* @since 2.0
*/
@Override
public NotificationChain inverseAdd(Object object, NotificationChain notifications)
{
CDOTransactionImpl transaction = cdoView().toTransaction();
InternalCDOObject cdoObject = FSMUtil.adapt(object, transaction);
notifications = cdoObject.eSetResource(CDOResourceImpl.this, notifications);
// Attach here instead of i CDOObjectImpl.eSetResource because EMF does it also here
if (FSMUtil.isTransient(cdoObject))
{
attached(cdoObject, transaction);
}
return notifications;
}
/**
* @since 2.0
*/
@Override
public NotificationChain inverseRemove(Object object, NotificationChain notifications)
{
InternalEObject eObject = (InternalEObject)object;
detached(eObject);
return eObject.eSetResource(null, notifications);
}
}
/**
* TODO Change superclass to NotifyingInternalEListImpl when EMF 2.3 is out of maintenance
* <p>
* TODO Reuse {@link ResourceImpl.ContentsEList}!!! --> Bugzilla!
*
* @ADDED
* @author Eike Stepper
*/
protected class TransientContents<E extends Object & EObject> extends NotifyingInternalEListImpl<E>
{
private static final long serialVersionUID = 1L;
public TransientContents()
{
}
public TransientContents(Collection<? extends E> collection)
{
super(collection);
}
public TransientContents(int initialCapacity)
{
super(initialCapacity);
}
/**
* Optimization taken from ResourceImpl.EContentList.contains
*
* @since 2.0
*/
@Override
public boolean contains(Object object)
{
return size <= 4 ? super.contains(object) : object instanceof InternalEObject
&& ((InternalEObject)object).eDirectResource() == CDOResourceImpl.this;
}
@Override
public Object getNotifier()
{
return CDOResourceImpl.this;
}
@Override
public int getFeatureID()
{
return EresourcePackage.CDO_RESOURCE__CONTENTS;
}
@Override
protected boolean isNotificationRequired()
{
return eNotificationRequired();
}
@Override
protected boolean useEquals()
{
return false;
}
@Override
protected boolean hasInverse()
{
return true;
}
@Override
protected boolean isUnique()
{
return true;
}
/**
* @since 2.0
*/
/*
* IMPORTANT: Compile errors in this method might indicate an old version of EMF. Legacy support is only enabled for
* EMF with fixed bug #247130. These compile errors do not affect native models!
*/
public InternalEList<E> readWriteFiringList()
{
return this;
}
@Override
public NotificationChain inverseAdd(E object, NotificationChain notifications)
{
InternalEObject eObject = (InternalEObject)object;
notifications = eObject.eSetResource(CDOResourceImpl.this, notifications);
// CDOResourceImpl.this.attached(eObject);
return notifications;
}
@Override
public NotificationChain inverseRemove(E object, NotificationChain notifications)
{
InternalEObject eObject = (InternalEObject)object;
// CDOResourceImpl.this.detached(eObject);
return eObject.eSetResource(null, notifications);
}
@Override
protected void didAdd(int index, E object)
{
super.didAdd(index, object);
modified();
}
@Override
protected void didRemove(int index, E object)
{
super.didRemove(index, object);
modified();
}
@Override
protected void didSet(int index, E newObject, E oldObject)
{
super.didSet(index, newObject, oldObject);
modified();
}
@Override
protected void didClear(int oldSize, Object[] oldData)
{
if (oldSize == 0)
{
loaded();
}
else
{
super.didClear(oldSize, oldData);
}
}
/**
* @since 2.0
*/
protected void loaded()
{
if (!isLoaded())
{
Notification notification = setLoaded(true);
if (notification != null)
{
eNotify(notification);
}
}
}
protected void modified()
{
if (isTrackingModification())
{
setModified(true);
}
}
}
} // CDOResourceImpl