blob: 2abcad2eed3efab9ac1eeab278931f8d5fd38f6d [file] [log] [blame]
/*
* Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others.
* 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 - maintenance
*/
package org.eclipse.emf.cdo.eresource.impl;
import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.CDOState;
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.transaction.CDOTransaction;
import org.eclipse.emf.cdo.util.CDOModificationTrackingAdapter;
import org.eclipse.emf.cdo.util.CDOURIUtil;
import org.eclipse.emf.cdo.util.CDOUtil;
import org.eclipse.emf.cdo.util.CommitException;
import org.eclipse.emf.cdo.util.ReadOnlyException;
import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.emf.cdo.view.CDOViewProvider;
import org.eclipse.emf.cdo.view.CDOViewProviderRegistry;
import org.eclipse.emf.internal.cdo.bundle.OM;
import org.eclipse.emf.internal.cdo.view.CDOStateMachine;
import org.eclipse.net4j.util.WrappedException;
import org.eclipse.net4j.util.collection.Pair;
import org.eclipse.net4j.util.transaction.TransactionException;
import org.eclipse.emf.common.notify.Adapter;
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.EReference;
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.xmi.XMIResource;
import org.eclipse.emf.ecore.xmi.XMLHelper;
import org.eclipse.emf.ecore.xmi.impl.XMIHelperImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
import org.eclipse.emf.spi.cdo.FSMUtil;
import org.eclipse.emf.spi.cdo.InternalCDOObject;
import org.eclipse.emf.spi.cdo.InternalCDOTransaction;
import org.eclipse.emf.spi.cdo.InternalCDOView;
import org.eclipse.emf.spi.cdo.InternalCDOViewSet;
import org.eclipse.core.runtime.IProgressMonitor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* <!-- begin-user-doc --> An implementation of the model object '<em><b>CDO Resource</b></em>'.
*
* @extends Resource.Internal
* @noextend This interface is not intended to be extended by clients. <!-- 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 CDOResourceLeafImpl implements CDOResource, Resource.Internal
{
private static final EReference CDO_RESOURCE_CONTENTS = EresourcePackage.eINSTANCE.getCDOResource_Contents();
/**
* The default URI converter when there is no resource set.
*
* @ADDED
*/
private static URIConverter defaultURIConverter;
/**
* @ADDED
*/
private boolean root;
/**
* @ADDED
*/
private URI initialURI;
/**
* TODO Set to true in commit()?
*
* @ADDED
*/
private boolean existing;
/**
* @ADDED
*/
private boolean loading;
/**
* @ADDED
*/
private boolean loaded;
/**
* @ADDED
*/
private boolean modified;
/**
* @ADDED
*/
private EList<Diagnostic> errors;
/**
* @ADDED
*/
private EList<Diagnostic> warnings;
/**
* @ADDED
*/
private transient CDOViewProvider viewProvider;
/**
* @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;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
* @since 2.0
*/
@Override
public Resource.Internal eDirectResource()
{
if (isRoot())
{
return this;
}
return super.eDirectResource();
}
@Override
public int eDerivedStructuralFeatureID(int baseFeatureID, Class<?> baseClass)
{
if (baseClass == CDOResource.class)
{
return baseFeatureID;
}
if (baseClass == Resource.class)
{
return baseFeatureID + EresourcePackage.CDO_RESOURCE_NODE_FEATURE_COUNT;
}
return super.eBaseStructuralFeatureID(baseFeatureID, baseClass);
}
@Override
public int eBaseStructuralFeatureID(int derivedFeatureID, Class<?> baseClass)
{
if (baseClass == CDOResource.class)
{
return derivedFeatureID;
}
if (baseClass == Resource.class)
{
return derivedFeatureID - EresourcePackage.CDO_RESOURCE_NODE_FEATURE_COUNT;
}
return super.eBaseStructuralFeatureID(derivedFeatureID, baseClass);
}
/**
* @since 2.0
*/
public boolean isRoot()
{
return root;
}
/**
* @since 3.0
*/
public 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
*/
@Override
public URI getURI()
{
if (cdoID() == null && initialURI != null)
{
return initialURI;
}
if (viewProvider != null)
{
URI uri = viewProvider.getResourceURI(cdoView(), getPath());
if (uri != null)
{
return uri;
}
}
return super.getURI();
}
/**
* <!-- 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()
{
return (EList<EObject>)eGet(EresourcePackage.Literals.CDO_RESOURCE__CONTENTS, true);
}
/**
* @since 2.0
*/
@Override
public void cdoInternalPostDetach(boolean remote)
{
super.cdoInternalPostDetach(remote);
if (remote)
{
existing = false;
}
removeFromResourceSet();
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
public boolean isModified()
{
return modified;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
public void setModified(boolean newModified)
{
boolean oldModified = modified;
modified = newModified;
if (oldModified != newModified && eNotificationRequired())
{
Notification notification = new NotificationImpl(Notification.SET, oldModified, newModified)
{
@Override
public Object getNotifier()
{
return CDOResourceImpl.this;
}
@Override
public int getFeatureID(Class<?> expectedClass)
{
return RESOURCE__IS_MODIFIED;
}
};
eNotify(notification);
}
}
/**
* <!-- 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)
{
// TODO FIX bug 265136
return Resource.RESOURCE__IS_LOADED;
}
};
return notification;
}
return null;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public boolean isTrackingModification()
{
return (Boolean)eGet(EresourcePackage.Literals.CDO_RESOURCE__TRACKING_MODIFICATION, true);
}
/**
* <!-- begin-user-doc -->
*
* @since 4.0 <!-- end-user-doc -->
* @generated
*/
public void setTrackingModificationGen(boolean newTrackingModification)
{
eSet(EresourcePackage.Literals.CDO_RESOURCE__TRACKING_MODIFICATION, newTrackingModification);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
public void setTrackingModification(boolean newTrackingModification)
{
if (cdoView().isReadOnly())
{
throw new ReadOnlyException("Underlying view is read-only");
}
if (newTrackingModification == isTrackingModification())
{
return;
}
EList<Adapter> adapters = eAdapters();
if (newTrackingModification)
{
adapters.add(new CDOModificationTrackingAdapter(this));
}
else
{
for (Adapter adapter : adapters)
{
if (adapter instanceof CDOModificationTrackingAdapter)
{
adapters.remove(adapter);
break;
}
}
}
setTrackingModificationGen(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);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public void setTimeStamp(long newTimeStamp)
{
eSet(EresourcePackage.Literals.CDO_RESOURCE__TIME_STAMP, 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)
{
if (uriFragment == null)
{
return null;
}
try
{
EObject eObjectByFragment = getEObjectByFragment(uriFragment);
if (eObjectByFragment != null)
{
return eObjectByFragment;
}
CDOID id = CDOIDUtil.read(uriFragment);
InternalCDOView view = cdoView();
if (CDOIDUtil.isNull(id) || view.isObjectNew(id) && !view.isObjectRegistered(id))
{
return null;
}
if (id.isObject())
{
CDOObject object = view.getObject(id, true);
return CDOUtil.getEObject(object);
}
}
catch (Exception ex)
{
// Do nothing
// Return null if the object cannot be resolved.
}
// If it doesn't match to anything we return null like ResourceImpl.getEObject
return null;
}
private EObject getEObjectByFragment(String uriFragment)
{
int length = uriFragment.length();
if (length > 0)
{
if (uriFragment.charAt(0) == '/')
{
ArrayList<String> uriFragmentPath = new ArrayList<String>(4);
int start = 1;
for (int i = 1; i < length; ++i)
{
if (uriFragment.charAt(i) == '/')
{
uriFragmentPath.add(start == i ? "" : uriFragment.substring(start, i));
start = i + 1;
}
}
uriFragmentPath.add(uriFragment.substring(start));
return getEObject(uriFragmentPath);
}
else if (uriFragment.charAt(length - 1) == '?')
{
int index = uriFragment.lastIndexOf('?', length - 2);
if (index > 0)
{
uriFragment = uriFragment.substring(0, index);
}
}
}
return null;
}
private EObject getEObject(List<String> uriFragmentPath)
{
int size = uriFragmentPath.size();
EObject eObject = getEObjectForURIFragmentRootSegment(size == 0 ? "" : uriFragmentPath.get(0));
for (int i = 1; i < size && eObject != null; ++i)
{
eObject = ((InternalEObject)eObject).eObjectForURIFragmentSegment(uriFragmentPath.get(i));
}
return eObject;
}
private EObject getEObjectForURIFragmentRootSegment(String uriFragmentRootSegment)
{
int position = 0;
if (uriFragmentRootSegment.length() > 0)
{
try
{
position = Integer.parseInt(uriFragmentRootSegment);
}
catch (NumberFormatException exception)
{
throw new RuntimeException(exception);
}
}
List<EObject> contents = getContents();
if (position < contents.size() && position >= 0)
{
return contents.get(position);
}
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();
}
/**
* @since 2.0
*/
@Override
public void cdoInternalPreLoad()
{
try
{
load(null);
}
catch (IOException ex)
{
throw WrappedException.wrap(ex);
}
}
/**
* @ADDED
*/
public void load(InputStream inputStream, Map<?, ?> options) throws IOException
{
// final String baseURI = getBaseURIOption(options);
// final Map<Resource, CDOResource> resourceMappings = new HashMap<Resource, CDOResource>();
//
// class ImportResource extends XMIResourceImpl
// {
// private CDOResource delegate;
//
// public ImportResource(CDOResource delegate)
// {
// super(URI.createURI(baseURI + delegate.getPath()));
// this.delegate = delegate;
// }
//
// @Override
// public EList<EObject> getContents()
// {
// return delegate.getContents();
// }
//
// @Override
// public String getURIFragment(EObject eObject)
// {
// String id = EcoreUtil.getID(eObject);
// if (id != null)
// {
// return id;
// }
//
// InternalEObject internalEObject = (InternalEObject)eObject;
// if (getMappedResource(internalEObject.eDirectResource()) == this)
// {
// return "/" + getURIFragmentRootSegment(eObject);
// }
//
// List<String> uriFragmentPath = new ArrayList<String>();
// boolean isContained = false;
// for (InternalEObject container = internalEObject.eInternalContainer(); container != null; container =
// internalEObject
// .eInternalContainer())
// {
// uriFragmentPath.add(container.eURIFragmentSegment(internalEObject.eContainingFeature(), internalEObject));
// internalEObject = container;
// if (getMappedResource(container.eDirectResource()) == this)
// {
// isContained = true;
// break;
// }
// }
//
// if (!isContained)
// {
// return "/-1";
// }
//
// StringBuilder result = new StringBuilder("/");
// result.append(getURIFragmentRootSegment(internalEObject));
//
// for (int i = uriFragmentPath.size() - 1; i >= 0; --i)
// {
// result.append('/');
// result.append(uriFragmentPath.get(i));
// }
//
// return result.toString();
// }
//
// @Override
// protected XMLHelper createXMLHelper()
// {
// return new XMIHelperImpl(this)
// {
// @Override
// public String getHREF(EObject obj)
// {
// InternalEObject o = (InternalEObject)obj;
//
// URI objectURI = o.eProxyURI();
// if (objectURI == null)
// {
// Resource otherResource = obj.eResource();
// otherResource = getMappedResource(otherResource);
// objectURI = getHREF(otherResource, obj);
// }
//
// objectURI = deresolve(objectURI);
// return objectURI.toString();
// }
//
// @Override
// protected URI getHREF(Resource otherResource, EObject obj)
// {
// String uriFragment = getURIFragment(otherResource, obj);
// if (otherResource == ImportResource.this)
// {
// return URI.createURI(uriFragment);
// }
//
// return otherResource.getURI().appendFragment(uriFragment);
// }
// };
// }
//
// private Resource getMappedResource(Resource otherResource)
// {
// Resource resource = resourceMappings.get(otherResource);
// if (resource != null)
// {
// return resource;
// }
//
// if (otherResource instanceof CDOResource)
// {
// CDOResource cdoResource = (CDOResource)otherResource;
// otherResource = new ImportResource(cdoResource);
// resourceMappings.put(cdoResource, otherResource);
// }
//
// return otherResource;
// }
// }
//
// XMIResource xmiResource = new ImportResource(this);
// resourceMappings.put(this, xmiResource);
// xmiResource.save(outputStream, options);
throw new UnsupportedOperationException();
}
/**
* @ADDED
*/
public void load(Map<?, ?> options) throws IOException
{
if (!isLoaded())
{
InternalCDOView view = cdoView();
if (!FSMUtil.isTransient(this))
{
CDOID id = cdoID();
if (id == null)
{
registerProxy(view);
}
else
{
synchronized (view)
{
if (!view.isObjectRegistered(id))
{
registerProxy(view);
}
}
}
}
Notification notification = setLoaded(true);
if (notification != null)
{
eNotify(notification);
}
// 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);
// // }
// }
}
}
private void registerProxy(InternalCDOView view) throws IOWrappedException
{
try
{
view.registerProxyResource(this);
}
catch (Exception ex)
{
OM.LOG.error(ex);
setExisting(false);
cdoInternalSetState(CDOState.TRANSIENT);
throw new IOWrappedException(ex);
}
}
/**
* 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
*/
@SuppressWarnings("unused")
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
{
CDOTransaction transaction = getTransaction(options);
IProgressMonitor progressMonitor = options != null ? (IProgressMonitor)options
.get(CDOResource.OPTION_SAVE_PROGRESS_MONITOR) : null;
try
{
transaction.commit(progressMonitor);
}
catch (CommitException ex)
{
throw new TransactionException(ex);
}
setModified(false);
}
/**
* @ADDED
*/
private CDOTransaction getTransaction(Map<?, ?> options)
{
CDOTransaction transaction = options != null ? (CDOTransaction)options
.get(CDOResource.OPTION_SAVE_OVERRIDE_TRANSACTION) : null;
if (transaction == null)
{
CDOView view = cdoView();
if (view instanceof CDOTransaction)
{
transaction = (CDOTransaction)view;
}
else
{
throw new IllegalStateException("No transaction available");
}
}
return transaction;
}
/**
* @ADDED
*/
public void save(OutputStream outputStream, Map<?, ?> options) throws IOException
{
final String baseURI = getBaseURIOption(options);
final Map<CDOResource, Resource> resourceMappings = new HashMap<CDOResource, Resource>();
class ExportResource extends XMIResourceImpl
{
private CDOResource delegate;
public ExportResource(CDOResource delegate)
{
super(URI.createURI(baseURI + delegate.getPath()));
this.delegate = delegate;
}
@Override
public EList<EObject> getContents()
{
return delegate.getContents();
}
// @Override
// public String getURIFragment(EObject eObject)
// {
// String id = EcoreUtil.getID(eObject);
// if (id != null)
// {
// return id;
// }
//
// InternalEObject internalEObject = (InternalEObject)eObject;
// if (getMappedResource(internalEObject.eDirectResource()) == this)
// {
// return "/" + getURIFragmentRootSegment(eObject);
// }
//
// List<String> uriFragmentPath = new ArrayList<String>();
// boolean isContained = false;
// for (InternalEObject container = internalEObject.eInternalContainer(); container != null; container =
// internalEObject
// .eInternalContainer())
// {
// uriFragmentPath.add(container.eURIFragmentSegment(internalEObject.eContainingFeature(), internalEObject));
// internalEObject = container;
// if (getMappedResource(container.eDirectResource()) == this)
// {
// isContained = true;
// break;
// }
// }
//
// if (!isContained)
// {
// return "/-1";
// }
//
// StringBuilder result = new StringBuilder("/");
// result.append(getURIFragmentRootSegment(internalEObject));
//
// for (int i = uriFragmentPath.size() - 1; i >= 0; --i)
// {
// result.append('/');
// result.append(uriFragmentPath.get(i));
// }
//
// return result.toString();
// }
@Override
protected boolean useUUIDs()
{
return true;
}
@Override
protected boolean useIDAttributes()
{
return false;
}
@Override
public String getID(EObject eObject)
{
CDOObject cdoObject = CDOUtil.getCDOObject(eObject);
StringBuilder builder = new StringBuilder();
CDOIDUtil.write(builder, cdoObject.cdoID());
return builder.toString();
}
@Override
protected XMLHelper createXMLHelper()
{
return new XMIHelperImpl(this)
{
@Override
public String getHREF(EObject obj)
{
InternalEObject o = (InternalEObject)obj;
URI objectURI = o.eProxyURI();
if (objectURI == null)
{
Resource otherResource = obj.eResource();
otherResource = getMappedResource(otherResource);
objectURI = getHREF(otherResource, obj);
}
objectURI = deresolve(objectURI);
return objectURI.toString();
}
@Override
protected URI getHREF(Resource otherResource, EObject obj)
{
String uriFragment = getURIFragment(otherResource, obj);
if (otherResource == ExportResource.this)
{
return URI.createURI(uriFragment);
}
return otherResource.getURI().appendFragment(uriFragment);
}
};
}
private Resource getMappedResource(Resource otherResource)
{
Resource resource = resourceMappings.get(otherResource);
if (resource != null)
{
return resource;
}
if (otherResource instanceof CDOResource)
{
CDOResource cdoResource = (CDOResource)otherResource;
otherResource = new ExportResource(cdoResource);
resourceMappings.put(cdoResource, otherResource);
}
return otherResource;
}
}
XMIResource xmiResource = new ExportResource(this);
resourceMappings.put(this, xmiResource);
xmiResource.save(outputStream, options);
}
private String getBaseURIOption(Map<?, ?> options)
{
if (options != null)
{
String uri = (String)options.get(OPTION_SAVE_BASE_URI);
if (uri != null)
{
return uri;
}
}
return "cdo://";
}
/**
* @ADDED
*/
public void unload()
{
// Do nothing
}
/**
* @ADDED
*/
public void delete(Map<?, ?> options) throws IOException
{
if (FSMUtil.isTransient(this))
{
removeFromResourceSet();
}
else
{
if (isRoot())
{
throw new UnsupportedOperationException();
}
if (getFolder() == null)
{
InternalCDOView view = cdoView();
view.getRootResource().getContents().remove(this);
}
else
{
basicSetFolder(null, false);
}
}
}
private void removeFromResourceSet()
{
final ResourceSet resourceSet = getResourceSet();
if (resourceSet != null)
{
InternalCDOViewSet viewSet = (InternalCDOViewSet)CDOUtil.getViewSet(resourceSet);
viewSet.executeWithoutNotificationHandling(new Callable<Boolean>()
{
public Boolean call() throws Exception
{
resourceSet.getResources().remove(CDOResourceImpl.this);
return true;
}
});
}
}
/**
* @ADDED
*/
public void attached(EObject object)
{
if (!FSMUtil.isTransient(this))
{
InternalCDOTransaction transaction = cdoView().toTransaction();
InternalCDOObject cdoObject = FSMUtil.adapt(object, transaction);
if (CDOUtil.isLegacyObject(cdoObject) && FSMUtil.isClean(cdoObject))
{
// Bug 352204
return;
}
attached(cdoObject, transaction);
}
}
/**
* @ADDED
*/
private void attached(InternalCDOObject cdoObject, InternalCDOTransaction 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)
{
final ResourceSet oldResourceSet = getResourceSet();
if (oldResourceSet != null)
{
final NotificationChain finalNotifications = notifications;
InternalCDOViewSet viewSet = (InternalCDOViewSet)CDOUtil.getViewSet(oldResourceSet);
notifications = viewSet.executeWithoutNotificationHandling(new Callable<NotificationChain>()
{
public NotificationChain call() throws Exception
{
return ((InternalEList<Resource>)oldResourceSet.getResources()).basicRemove(this, finalNotifications);
}
});
}
setResourceSet(resourceSet);
if (resourceSet != null)
{
InternalCDOView view = cdoView();
if (view == null)
{
URI uri = getURI();
Pair<CDOView, CDOViewProvider> pair = CDOViewProviderRegistry.INSTANCE.provideViewWithInfo(uri, resourceSet);
if (pair != null)
{
view = (InternalCDOView)pair.getElement1();
view.attachResource(this);
viewProvider = pair.getElement2();
}
}
}
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
* @since 3.0
*/
protected void setExisting(boolean existing)
{
this.existing = existing;
}
/**
* @ADDED
*/
@Override
protected EList<?> createList(EStructuralFeature eStructuralFeature)
{
if (eStructuralFeature == CDO_RESOURCE_CONTENTS)
{
return new ContentsCDOList(CDO_RESOURCE_CONTENTS);
// return new _ContentsCDOList<EObject>();
}
return super.createList(eStructuralFeature);
}
// /**
// * A notifying list implementation for supporting {@link Resource#getContents}.
// */
// protected class _ContentsCDOList<E extends Object & EObject> extends ResourceContentsEList<E>
// {
// private static final long serialVersionUID = 1L;
//
// @Override
// public int getFeatureID()
// {
// return CDO_RESOURCE_CONTENTS.getFeatureID();
// }
//
// @Override
// protected CDOResourceImpl getResource()
// {
// return CDOResourceImpl.this;
// }
//
// @Override
// protected Notification setLoaded(boolean loaded)
// {
// return getResource().setLoaded(loaded);
// }
//
// @Override
// protected boolean isNotificationRequired()
// {
// return getResource().eNotificationRequired();
// }
//
// @Override
// public NotificationChain inverseAdd(E object, NotificationChain notifications)
// {
// if (FSMUtil.isTransient(getResource()))
// {
// InternalEObject eObject = (InternalEObject)object;
// return eObject.eSetResource(CDOResourceImpl.this, notifications);
// // return super.inverseAdd(object, notifications);
// }
//
// InternalCDOTransaction transaction = cdoView().toTransaction();
// InternalCDOObject cdoObject = FSMUtil.adapt(object, transaction);
// notifications = cdoObject.eSetResource(getResource(), notifications);
//
// // Attach here instead of in CDOObjectImpl.eSetResource because EMF does it also here
// if (FSMUtil.isTransient(cdoObject))
// {
// attached(cdoObject, transaction);
// }
//
// return notifications;
// }
//
// @Override
// public NotificationChain inverseRemove(E object, NotificationChain notifications)
// {
// if (FSMUtil.isTransient(getResource()))
// {
// InternalEObject eObject = (InternalEObject)object;
// return eObject.eSetResource(null, notifications);
// // return super.inverseRemove(object, notifications);
// }
//
// InternalEObject eObject = (InternalEObject)object;
// detached(eObject);
// return eObject.eSetResource(null, notifications);
// }
// }
/**
* An implementation of a CDO specific '<em><b>contents</b></em>' list.
*
* @ADDED
* @author Eike Stepper
* @since 2.0
*/
protected class ContentsCDOList extends BasicEStoreEList<Object>
{
private static final long serialVersionUID = 1L;
public ContentsCDOList(EStructuralFeature eStructuralFeature)
{
super(CDOResourceImpl.this, eStructuralFeature);
}
/**
* Optimization taken from ResourceImpl.EContentList.contains.
*
* @since 2.0
*/
@Override
public boolean contains(Object object)
{
if (size() <= 4)
{
return super.contains(object);
}
return object instanceof InternalEObject && ((InternalEObject)object).eDirectResource() == CDOResourceImpl.this;
}
/**
* @since 2.0
*/
@Override
public NotificationChain inverseAdd(Object object, NotificationChain notifications)
{
if (FSMUtil.isTransient(CDOResourceImpl.this))
{
InternalEObject eObject = (InternalEObject)object;
notifications = eObject.eSetResource(CDOResourceImpl.this, notifications);
}
else
{
InternalCDOTransaction transaction = cdoView().toTransaction();
InternalCDOObject cdoObject = FSMUtil.adapt(object, transaction);
notifications = cdoObject.eSetResource(CDOResourceImpl.this, notifications);
// Attach here instead of in 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)
{
if (FSMUtil.isTransient(CDOResourceImpl.this))
{
InternalEObject eObject = (InternalEObject)object;
notifications = eObject.eSetResource(null, notifications);
}
else
{
InternalEObject eObject = (InternalEObject)object;
detached(eObject);
notifications = eObject.eSetResource(null, notifications);
}
return notifications;
}
/**
* @since 2.0
*/
protected void loaded()
{
Notification notification = setLoaded(true);
if (notification != null)
{
eNotify(notification);
}
}
/**
* @since 2.0
*/
protected void modified()
{
if (isTrackingModification())
{
setModified(true);
}
}
/**
* @since 2.0
*/
@Override
protected boolean useEquals()
{
return false;
}
/**
* @since 2.0
*/
@Override
protected boolean hasInverse()
{
return true;
}
/**
* @since 2.0
*/
@Override
protected boolean isUnique()
{
return true;
}
/**
* @since 4.0
*/
@Override
protected void didAdd(int index, Object newObject)
{
super.didAdd(index, newObject);
if (!isExisting() && !isLoaded())
{
loaded();
}
}
/**
* @since 4.0
*/
@Override
protected void didClear(int size, Object[] oldObjects)
{
super.didClear(size, oldObjects);
if (!isExisting() && !isLoaded())
{
loaded();
}
}
}
} // CDOResourceImpl