| //------------------------------------------------------------------------------ |
| // Copyright (c) 2005, 2006 IBM Corporation 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: |
| // IBM Corporation - initial implementation |
| //------------------------------------------------------------------------------ |
| package org.eclipse.epf.persistence; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.emf.common.CommonPlugin; |
| import org.eclipse.emf.common.notify.Adapter; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.util.AbstractTreeIterator; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EAttribute; |
| import org.eclipse.emf.ecore.EObject; |
| 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.util.EContentsEList; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.emf.ecore.xmi.XMLHelper; |
| import org.eclipse.emf.ecore.xmi.XMLLoad; |
| import org.eclipse.emf.ecore.xmi.XMLSave; |
| import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; |
| import org.eclipse.epf.common.utils.FileUtil; |
| import org.eclipse.epf.library.persistence.ILibraryResource; |
| import org.eclipse.epf.library.persistence.internal.IFailSafeSavable; |
| import org.eclipse.epf.persistence.refresh.RefreshJob; |
| import org.eclipse.epf.persistence.util.PersistenceResources; |
| import org.eclipse.epf.persistence.util.PersistenceUtil; |
| import org.eclipse.epf.resourcemanager.ResourceDescriptor; |
| import org.eclipse.epf.resourcemanager.ResourceManager; |
| import org.eclipse.epf.services.ILibraryPersister; |
| import org.eclipse.epf.uma.ContentDescription; |
| import org.eclipse.epf.uma.MethodConfiguration; |
| import org.eclipse.epf.uma.MethodElement; |
| import org.eclipse.epf.uma.MethodLibrary; |
| import org.eclipse.epf.uma.MethodPlugin; |
| import org.eclipse.epf.uma.Process; |
| import org.eclipse.epf.uma.ProcessComponent; |
| import org.eclipse.epf.uma.Section; |
| import org.eclipse.epf.uma.UmaPackage; |
| import org.eclipse.epf.uma.ecore.impl.MultiResourceEObject; |
| import org.eclipse.epf.uma.ecore.util.DefaultValueManager; |
| import org.eclipse.epf.uma.ecore.util.OppositeFeatureNotification; |
| import org.eclipse.epf.uma.util.Scope; |
| import org.eclipse.epf.uma.util.UmaUtil; |
| import org.eclipse.osgi.util.NLS; |
| |
| /** |
| * Resource implementation for library XMI persistence |
| * |
| * @author Phong Nguyen Le |
| * @since 1.0 |
| */ |
| public class MultiFileXMIResourceImpl extends XMIResourceImpl |
| implements ILibraryResource, IFailSafeSavable |
| { |
| |
| private static String tempDir; |
| |
| private URI finalURI; |
| |
| private URI oldURI; |
| |
| private String backupFile; |
| |
| private String currentTxID; |
| |
| private long lastLoadTimeStamp; |
| |
| private ResourceDescriptor resourceDescriptor; |
| |
| private boolean isUnloading; |
| |
| /** Cached modification stamp of the resource file */ |
| private long modificationStamp; |
| |
| private IFileInfo fileInfo; |
| |
| public MultiFileXMIResourceImpl(URI uri) { |
| super(uri); |
| setIntrinsicIDToEObjectMap(new HashMap()); |
| } |
| |
| protected XMLLoad createXMLLoad() { |
| return new MultiFileXMILoadImpl(createXMLHelper()); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl#createXMLSave() |
| */ |
| protected XMLSave createXMLSave() { |
| return new MultiFileXMISaveImpl(createXMLHelper()); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl#createXMLHelper() |
| */ |
| protected XMLHelper createXMLHelper() { |
| return new MultiFileXMIHelperImpl(this); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.xmi.XMLResource#getID(org.eclipse.emf.ecore.EObject) |
| */ |
| public String getID(EObject eObject) { |
| String id = MultiFileSaveUtil.getGuid(eObject); |
| if (id != null) |
| return id; |
| return super.getID(eObject); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl#setID(org.eclipse.emf.ecore.EObject, |
| * java.lang.String) |
| */ |
| public void setID(EObject eObject, String id) { |
| Object oldID = id != null ? getEObjectToIDMap().put(eObject, id) |
| : getEObjectToIDMap().remove(eObject); |
| |
| Map guidToMethodElementMap = ((MultiFileResourceSetImpl) getResourceSet()) |
| .getGuidToMethodElementMap(); |
| |
| if (oldID != null) { |
| getIDToEObjectMap().remove(oldID); |
| |
| if (eObject instanceof MethodElement) { |
| // remove object from guidToMethodElementMap only if it is a proxy |
| // |
| if(eObject.eIsProxy()) { |
| EObject obj = (EObject) guidToMethodElementMap.get(id); |
| if(obj != null && obj.eIsProxy()) { |
| guidToMethodElementMap.remove(id); |
| } |
| } |
| else { |
| guidToMethodElementMap.remove(id); |
| } |
| } |
| } |
| |
| if (id != null) { |
| getIDToEObjectMap().put(id, eObject); |
| if (eObject instanceof MethodElement) { |
| guidToMethodElementMap.put(id, eObject); |
| |
| MethodElement e = (MethodElement) eObject; |
| if (!e.getGuid().equals(id)) { |
| e.setGuid(id); |
| } |
| } |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl#useUUIDs() |
| */ |
| protected boolean useUUIDs() { |
| return true; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.resource.Resource#getURIFragment(org.eclipse.emf.ecore.EObject) |
| */ |
| public String getURIFragment(EObject eObject) { |
| try { |
| String id = getID(eObject); |
| |
| if (id != null) { |
| return id; |
| } else { |
| List uriFragmentPath = new ArrayList(); |
| for (EObject container = eObject.eContainer(); container != null |
| && container.eResource() == this; container = eObject |
| .eContainer()) { |
| uriFragmentPath.add(((InternalEObject) container) |
| .eURIFragmentSegment(eObject.eContainingFeature(), |
| eObject)); |
| eObject = container; |
| } |
| |
| StringBuffer result = new StringBuffer("/"); //$NON-NLS-1$ |
| result.append(getURIFragmentRootSegment(eObject)); |
| |
| for (ListIterator i = uriFragmentPath |
| .listIterator(uriFragmentPath.size()); i.hasPrevious();) { |
| result.append('/'); |
| result.append((String) i.previous()); |
| } |
| return result.toString(); |
| } |
| } catch (RuntimeException e) { |
| System.err.println("Error getting URI fragment for " + eObject); //$NON-NLS-1$ |
| throw e; |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl#attachedHelper(org.eclipse.emf.ecore.EObject) |
| */ |
| protected void attachedHelper(EObject eObject) { |
| super.attachedHelper(eObject); |
| |
| if (useIDs()) { |
| String id = getID(eObject); |
| if (id != null) { |
| // update the eObjectToIDMap |
| // |
| getEObjectToIDMap().put(eObject, id); |
| |
| if (eObject instanceof MethodElement) { |
| ((MultiFileResourceSetImpl) getResourceSet()) |
| .getGuidToMethodElementMap().put(id, eObject); |
| } |
| } |
| } |
| |
| if (isTrackingModification() && eObject.eResource() != this) { |
| // remove the modification tracking adapter from the eObject |
| // |
| eObject.eAdapters().remove(modificationTrackingAdapter); |
| } |
| } |
| |
| private void attachedAllWithIDs(EObject eObj) { |
| // attachedHelper(eObj); |
| // List list = eObj.eContents(); |
| // int size = list.size(); |
| // for (int i = 0; i < size; i++) { |
| // EObject o = (EObject) list.get(i); |
| // if (o.eResource() == this) { |
| // attachedAllWithIDs(o); |
| // } |
| // } |
| |
| Iterator allContents = new ContentTreeIterator(eObj); |
| |
| while (allContents.hasNext()) { |
| attachedHelper((EObject) allContents.next()); |
| } |
| } |
| |
| private void basicAttachedAll(EObject eObj) { |
| eObj.eAdapters().add(modificationTrackingAdapter); |
| List list = eObj.eContents(); |
| int size = list.size(); |
| for (int i = 0; i < size; i++) { |
| EObject o = (EObject) list.get(i); |
| if (o.eResource() == this) { |
| basicAttachedAll(o); |
| } |
| } |
| } |
| |
| /** |
| * Calls on an object and all of its offstring objects that are in the same |
| * resource as the object when the object is attached to this resource. This |
| * method is expensive, so use it with caution. |
| * |
| * @param eObj |
| */ |
| public void attachedAll(EObject eObj) { |
| if (useIDs()) { |
| attachedAllWithIDs(eObj); |
| } else { |
| basicAttachedAll(eObj); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.resource.Resource.Internal#attached(org.eclipse.emf.ecore.EObject) |
| */ |
| public void attached(EObject eObject) { |
| attachedAll(eObject); |
| } |
| |
| private void detachedAllWithIDs(EObject eObj) { |
| Iterator allContents = new ContentTreeIterator(eObj); |
| |
| while (allContents.hasNext()) { |
| detachedHelper((EObject) allContents.next()); |
| } |
| } |
| |
| private void basicDetachedAll(EObject eObj) { |
| eObj.eAdapters().remove(modificationTrackingAdapter); |
| List list = eObj.eContents(); |
| int size = list.size(); |
| for (int i = 0; i < size; i++) { |
| EObject o = (EObject) list.get(i); |
| if (o.eResource() == this) { |
| basicDetachedAll(o); |
| } |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl#getEObjectByID(java.lang.String) |
| */ |
| protected EObject getEObjectByID(String id) { |
| for (Iterator iter = getContents().iterator(); iter.hasNext();) { |
| EObject element = (EObject) iter.next(); |
| String guid = MultiFileSaveUtil.getGuid(element); |
| if (guid != null && guid.equals(id)) |
| return element; |
| } |
| |
| // return super.getEObjectByID(id); |
| |
| if (idToEObjectMap != null) { |
| InternalEObject eObject = (InternalEObject) idToEObjectMap.get(id); |
| if (eObject != null && !eObject.eIsProxy()) { |
| return eObject; |
| } |
| } |
| |
| return null; |
| } |
| |
| private IFileInfo getFileInfo() { |
| if(fileInfo == null || !new File(getURI().toFileString()).equals(fileInfo.getFile())) { |
| fileInfo = FileManager.getInstance().getFileInfo(this); |
| } |
| return fileInfo; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.resource.impl.ResourceImpl#load(java.util.Map) |
| */ |
| public void load(Map options) throws IOException { |
| if (isUnloading) { |
| return; |
| } |
| |
| boolean old = DefaultValueManager.INSTANCE.isUseStatic(); |
| try { |
| DefaultValueManager.INSTANCE.setUseStatic(true); |
| super.load(options); |
| updateTimeStamps(); |
| } |
| finally { |
| DefaultValueManager.INSTANCE.setUseStatic(old); |
| } |
| |
| if (MultiFileSaveUtil.DEBUG) { |
| if (getURI().toString().equals(testResourceURIStr)) { |
| testResourceLoaded = true; |
| } |
| } |
| } |
| |
| private static boolean testResourceLoaded; |
| |
| private static final String testResourceURIStr = "file:/C:/temp/newlib/library.xmi"; //$NON-NLS-1$ |
| |
| public long getModificationStamp() { |
| return modificationStamp; |
| } |
| |
| /** |
| * Reloads this resource. Old objects will become proxies and they will be |
| * added to the specified collection <code>proxies</code> |
| * |
| * @param proxies |
| */ |
| synchronized boolean reload(Collection proxies) throws IOException { |
| if (isLoaded) { |
| Notification notification = setLoaded(false); |
| doUnload(proxies, false); |
| // doUnload() might have set this resource loaded again |
| // set isLoaded to false and contents to null to make sure |
| // |
| isLoaded = false; |
| contents = null; |
| if (notification != null) { |
| eNotify(notification); |
| } |
| load(getResourceSet().getLoadOptions()); |
| return true; |
| } |
| return false; |
| } |
| |
| /* |
| * Javadoc copied from interface. |
| */ |
| final void unloadWithoutRemove() { |
| if (isLoaded) { |
| // save the ResourceDescriptor pf this resource for later use to |
| // create URI for the proxies after unload |
| // |
| ResourceDescriptor resDesc = MultiFileSaveUtil |
| .getResourceDescriptor(this); |
| if (resDesc != null) { |
| setResourceDescriptor(resDesc); |
| } |
| |
| Notification notification = setLoaded(false); |
| doUnload(null, false); |
| if (notification != null) { |
| eNotify(notification); |
| } |
| } |
| } |
| |
| /** |
| * Does all the work of unloading the resource. It calls |
| * {@link #unloaded unloaded} for each object it the content |
| * {@link #getAllContents tree}, and clears the |
| * {@link #getContents contents}, {@link #getErrors errors}, and |
| * {@link #getWarnings warnings}. |
| */ |
| protected void doUnload() { |
| doUnload(null, true); |
| } |
| |
| /** |
| * @author Phong Nguyen Le - Jul 17, 2006 |
| * @since 1.0 |
| */ |
| private final class ContentTreeIterator extends AbstractTreeIterator { |
| /** |
| * Comment for <code>serialVersionUID</code> |
| */ |
| private static final long serialVersionUID = 1L; |
| |
| /** |
| * @param object |
| */ |
| private ContentTreeIterator(Object object) { |
| super(object); |
| } |
| |
| protected Iterator getChildren(Object object) { |
| if (object instanceof EObject) { |
| ArrayList children = new ArrayList(); |
| EContentsEList contents = new EContentsEList((EObject) object) { |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.util.EContentsEList#resolve() |
| */ |
| protected boolean resolve() { |
| return false; |
| } |
| }; |
| for (Iterator iter = contents.basicIterator(); iter.hasNext();) { |
| EObject o = (EObject) iter.next(); |
| if (o.eResource() == MultiFileXMIResourceImpl.this |
| || o.eIsProxy()) { |
| children.add(o); |
| } |
| } |
| return children.iterator(); |
| } |
| return Collections.EMPTY_LIST.iterator(); |
| } |
| } |
| |
| /** |
| * Unloads this resource. Old objects will be come proxies and will be added |
| * to the specified collection <code>proxies</code> |
| * |
| * @param proxies |
| * @param remove |
| * if <code>true</code> will remove all the unloaded objects in |
| * the resource from their containers and all opposite feature |
| * data of the unloaded objects will be cleared. |
| */ |
| protected void doUnload(Collection proxies, boolean remove) { |
| isUnloading = true; |
| |
| try { |
| // from ResourceImpl |
| // |
| |
| Iterator allContents = getAllProperContents(new ArrayList( |
| getContents())); |
| |
| // This guard is needed to ensure that clear doesn't make the |
| // resource |
| // become loaded. |
| // |
| if (!getContents().isEmpty()) { |
| if (remove) { |
| getContents().clear(); |
| } else { |
| // don't call getContents().clear() to keep the references |
| // to elements |
| // that just became proxies after unload |
| // |
| contents = null; |
| } |
| |
| } |
| getErrors().clear(); |
| getWarnings().clear(); |
| |
| ArrayList<EObject> unloadedObjects = new ArrayList<EObject>(); |
| |
| ArrayList allContentList = new ArrayList(); |
| while (allContents.hasNext()) { |
| allContentList.add(allContents.next()); |
| } |
| Iterator it = allContentList.iterator(); |
| |
| try { |
| while (it.hasNext()) { |
| try { |
| InternalEObject o = (InternalEObject) it |
| .next(); |
| unloaded(o, remove); |
| unloadedObjects.add(o); |
| } catch (Exception e) { |
| CommonPlugin.INSTANCE.log(e); |
| } |
| } |
| } catch (Exception e) { |
| CommonPlugin.INSTANCE.log(e); |
| } |
| if (proxies != null && !unloadedObjects.isEmpty()) { |
| proxies.addAll(unloadedObjects); |
| } |
| if (remove) { |
| // remove the unloaded objects from its container to prevent the |
| // whole library from staying |
| // in memory if only one of its element is leaked |
| // |
| for (Iterator iter = unloadedObjects.iterator(); iter.hasNext();) { |
| EObject object = (EObject) iter.next(); |
| EcoreUtil.remove(object); |
| } |
| } |
| |
| // from XMLResourceIml |
| // |
| |
| if (idToEObjectMap != null) { |
| for (Iterator iter = idToEObjectMap.keySet().iterator(); iter |
| .hasNext();) { |
| ((MultiFileResourceSetImpl) getResourceSet()) |
| .getGuidToMethodElementMap().remove(iter.next()); |
| } |
| idToEObjectMap.clear(); |
| } |
| |
| if (eObjectToIDMap != null) { |
| eObjectToIDMap.clear(); |
| } |
| |
| if (eObjectToExtensionMap != null) { |
| eObjectToExtensionMap.clear(); |
| } |
| |
| if (intrinsicIDToEObjectMap != null) { |
| intrinsicIDToEObjectMap.clear(); |
| } |
| |
| modificationStamp = IResource.NULL_STAMP; |
| |
| } finally { |
| isUnloading = false; |
| } |
| } |
| |
| protected void unloaded(InternalEObject internalEObject) { |
| unloaded(internalEObject, true); |
| } |
| |
| /** |
| * @param internalEObject |
| * @param clear |
| * if <code>true</code> all opposite feature data of the |
| * unloaded objects will be cleared. |
| */ |
| private void unloaded(InternalEObject internalEObject, boolean clear) { |
| String guid = MultiFileSaveUtil.getGuid(internalEObject); |
| if (guid != null) { |
| URI uri = resourceDescriptor != null ? MultiFileURIConverter |
| .createURI(resourceDescriptor.getId()) : getURI(); |
| internalEObject.eSetProxyURI(uri.appendFragment(guid)); |
| } |
| internalEObject.eAdapters().clear(); |
| |
| if (internalEObject instanceof MultiResourceEObject && clear) { |
| MultiResourceEObject multiResourceEObject = ((MultiResourceEObject) internalEObject); |
| |
| // clear own opposite feature map |
| // |
| Map oppositeFeatureMap = multiResourceEObject |
| .basicGetOppositeFeatureMap(); |
| if (oppositeFeatureMap != null) { |
| oppositeFeatureMap.clear(); |
| } |
| |
| // remove itself from all opposite features |
| // |
| multiResourceEObject.removeFromAllOppositeFeatures(); |
| } |
| |
| if(internalEObject instanceof ContentDescription || internalEObject instanceof Section) { |
| // set all string attributes to NULL to release memory |
| // |
| for (EAttribute attr : internalEObject.eClass().getEAllAttributes()) { |
| if(attr != UmaPackage.eINSTANCE.getMethodElement_Guid() && |
| attr.getEAttributeType().getInstanceClass().isAssignableFrom(String.class)) { |
| internalEObject.eSet(attr, attr.getDefaultValue()); |
| } |
| } |
| |
| if(internalEObject.eDirectResource() != null && internalEObject instanceof MultiResourceEObject) { |
| ((MultiResourceEObject)internalEObject).eSetResource(null); |
| } |
| } |
| } |
| |
| public void detachedAll(EObject eObj) { |
| if (useIDs()) { |
| detachedAllWithIDs(eObj); |
| } else { |
| basicDetachedAll(eObj); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.resource.Resource.Internal#detached(org.eclipse.emf.ecore.EObject) |
| */ |
| public void detached(EObject eObject) { |
| detachedAll(eObject); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.resource.impl.ResourceImpl#createModificationTrackingAdapter() |
| */ |
| protected Adapter createModificationTrackingAdapter() { |
| return new ModificationTrackingAdapter() { |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.resource.impl.ResourceImpl.ModificationTrackingAdapter#notifyChanged(org.eclipse.emf.common.notify.Notification) |
| */ |
| public void notifyChanged(Notification notification) { |
| // don't handle OppositeFeatureNotification b/c it does not |
| // really modify this resource |
| // |
| if (notification instanceof OppositeFeatureNotification) { |
| return; |
| } |
| super.notifyChanged(notification); |
| } |
| }; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.ecore.resource.impl.ResourceImpl#setModified(boolean) |
| */ |
| public void setModified(boolean isModified) { |
| // boolean wasModified = isModified(); |
| super.setModified(isModified); |
| // if(MultiFileSaveUtil.getMethodElement(this) instanceof |
| // ProcessComponent) { |
| // System.out.println("MultiFileXMIResourceImpl.setModified(): " + |
| // this); |
| // } |
| // this code is needed to set dirty flag to the item provider's label |
| // |
| // if(wasModified != isModified && !getContents().isEmpty()) { |
| // // refresh the label of the resource's object |
| // // |
| // EObject obj = (EObject) getContents().get(0); |
| // for (Iterator iter = obj.eAdapters().iterator(); iter.hasNext();) { |
| // Object adapter = iter.next(); |
| // if(adapter instanceof ItemProviderAdapter) { |
| // ((ItemProviderAdapter)adapter).fireNotifyChanged(new |
| // ViewerNotification(new NotificationImpl(Notification.SET, obj, obj), |
| // obj, false, true)); |
| // } |
| // } |
| // } |
| |
| if (MultiFileSaveUtil.DEBUG) { |
| if (testResourceLoaded |
| && getURI().toString().equals(testResourceURIStr)) { |
| System.out.println("isModified=" + isModified); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifierImpl#eDeliver() |
| */ |
| public boolean eDeliver() { |
| ResourceSet resourceSet = getResourceSet(); |
| if (resourceSet != null && !resourceSet.eDeliver()) |
| return false; |
| |
| return super.eDeliver(); |
| } |
| |
| public void save(Map options) throws IOException { |
| boolean old = DefaultValueManager.INSTANCE.isUseStatic(); |
| |
| Process proc = null; |
| Scope scope = null; |
| |
| try { |
| DefaultValueManager.INSTANCE.setUseStatic(true); |
| |
| if (options == null) { |
| options = MultiFileResourceSetImpl.DEFAULT_SAVE_OPTIONS; |
| } |
| |
| MethodElement e = PersistenceUtil.getMethodElement(this); |
| if (e instanceof ProcessComponent) { |
| proc = ((ProcessComponent) e).getProcess(); |
| if (proc != null && proc.getDefaultContext() instanceof Scope) { |
| boolean oldDeliver = proc.eDeliver(); |
| try { |
| proc.eSetDeliver(false); |
| scope = (Scope) proc.getDefaultContext(); |
| proc.setDefaultContext(null); |
| proc.getValidContext().clear(); |
| } finally { |
| proc.eSetDeliver(oldDeliver); |
| } |
| } |
| } |
| |
| super.save(options); |
| |
| // Special handling for saving MethodLibrary to remove all references to |
| // MethodConfigurations from library file. |
| // |
| //MethodElement e = PersistenceUtil.getMethodElement(this); |
| |
| handleSynFreeFlag(e); |
| |
| if (e instanceof MethodLibrary) { |
| MethodLibrary lib = (MethodLibrary) e; |
| // remove ResourceDescriptors of configuration files |
| // |
| ResourceManager resMgr = MultiFileSaveUtil.getResourceManager(this); |
| if (resMgr != null) { |
| for (Iterator iter = lib.getPredefinedConfigurations() |
| .iterator(); iter.hasNext();) { |
| MethodConfiguration config = (MethodConfiguration) iter |
| .next(); |
| ResourceDescriptor resDesc = resMgr |
| .getResourceDescriptor(config.getGuid()); |
| if (resDesc != null) { |
| EcoreUtil.remove(resDesc); |
| } |
| } |
| } |
| List configs = new ArrayList(lib.getPredefinedConfigurations()); |
| boolean oldDeliver = lib.eDeliver(); |
| try { |
| lib.eSetDeliver(false); |
| lib.getPredefinedConfigurations().clear(); |
| |
| // Save library file again to remove all references to configurations. |
| // The previous save is still needed to save new configuration in its own file |
| // |
| super.save(options); |
| } finally { |
| lib.getPredefinedConfigurations().addAll(configs); |
| lib.eSetDeliver(oldDeliver); |
| } |
| } |
| } |
| finally { |
| DefaultValueManager.INSTANCE.setUseStatic(old); |
| if (proc != null && scope != null) { |
| boolean oldDeliver = proc.eDeliver(); |
| try { |
| proc.eSetDeliver(false); |
| proc.setDefaultContext(scope); |
| proc.getValidContext().add(scope); |
| } finally { |
| proc.eSetDeliver(oldDeliver); |
| } |
| } |
| } |
| } |
| |
| public URI getFinalURI() { |
| if (finalURI != null) { |
| return finalURI; |
| } |
| return getURI(); |
| } |
| |
| public void setFinalURI(URI uri) { |
| finalURI = uri; |
| } |
| |
| public void backUpURI() { |
| oldURI = getURI(); |
| } |
| |
| public boolean hasTempURI() { |
| if (currentTxID != null) { |
| return createTempURI().equals(getURI()); |
| } |
| return false; |
| } |
| |
| private URI createTempURI() { |
| MethodElement e = PersistenceUtil.getMethodElement(this); |
| return URI.createFileURI(new StringBuffer(getTempDir()).append( |
| File.separator).append(currentTxID) |
| .append("new").append(e.getGuid()).toString()); //$NON-NLS-1$ |
| } |
| |
| static String getTempDir() { |
| if (tempDir == null) { |
| tempDir = new File(FileManager.getTempDir(), "EPF").getAbsolutePath(); //$NON-NLS-1$ |
| } |
| return tempDir; |
| } |
| |
| /** |
| * Sets the temporary URI to save this resource to and it will be renamed to |
| * the original URI when saving is done |
| */ |
| public void setTempURI(String txID) { |
| if (finalURI == null) { |
| finalURI = oldURI = getURI(); |
| currentTxID = txID; |
| |
| URI tempURI = createTempURI(); |
| setURI(tempURI); |
| |
| MultiFileResourceSetImpl resourceSet = (MultiFileResourceSetImpl) getResourceSet(); |
| resourceSet.getURIToTempURIMap().put(oldURI, tempURI); |
| } |
| } |
| |
| /** |
| * Restores the resource URI to the original one. This method must be call |
| * after saving regarless of its success. |
| * |
| */ |
| private void restoreURI() { |
| if (oldURI != null) { |
| setURI(oldURI); |
| } |
| } |
| |
| public boolean txStarted() { |
| return moveStarted() || saveStarted(); |
| } |
| |
| protected void updateTimeStamps() { |
| FileManager.getInstance().refresh(this); |
| lastLoadTimeStamp = System.currentTimeMillis(); |
| IFileInfo info = getFileInfo(); |
| if(info != null) { |
| modificationStamp = info.getModificationStamp(); |
| } |
| } |
| |
| /** |
| * Checks if this resource is currently synchronized with its data store |
| * |
| * @return <li> -1 don't know |
| * <li> 0 no |
| * <li> 1 yes |
| * @deprecated use {@link #isSynchronized()} instead |
| */ |
| public int checkSynchronized() { |
| // long currentTime = new File(getURI().toFileString()).lastModified(); |
| // if(MultiFileSaveUtil.same(currentTime, fileLastModified)) { |
| // // some team providers changed the timestamp of last file modification by removing second fraction |
| // // even the file was not changed |
| // // |
| // return 1; |
| // } |
| // return -1; |
| return isSynchronized() ? 1 : 0; |
| } |
| |
| public boolean isSynchronized() { |
| IFileInfo fileInfo = getFileInfo(); |
| if (fileInfo != null) { |
| return modificationStamp == fileInfo.getModificationStamp(); |
| } |
| else { |
| return true; |
| } |
| } |
| |
| public void txFinished(boolean successful) { |
| boolean wasMove = !oldURI.equals(finalURI); |
| if (successful) { |
| setURI(finalURI); |
| if(!wasMove) { |
| setModified(false); |
| } |
| updateTimeStamps(); |
| if(!wasMove) { |
| MultiFileResourceSetImpl resourceSet = (MultiFileResourceSetImpl) getResourceSet(); |
| if(resourceSet != null) { |
| resourceSet.getUnresolvedProxyMarkerManager().validateMarkers(this); |
| } |
| } |
| } else { |
| restoreURI(); |
| if (wasMove) { |
| // finalURI must be cleared before restoring URI of its child |
| // resources so the URI of its child resources can be resolved |
| // correctly. See ResourceDescriptorImpl.getResolvedURI() |
| // |
| finalURI = null; |
| |
| // restore uri of ResourceDescriptor of this resource |
| // |
| MultiFileSaveUtil.updateURIMappings(this, oldURI, null, true); |
| } |
| } |
| if (oldURI != null) { |
| MultiFileResourceSetImpl resourceSet = (MultiFileResourceSetImpl) getResourceSet(); |
| if (resourceSet != null) { |
| resourceSet.getURIToTempURIMap().remove(oldURI); |
| } |
| oldURI = null; |
| } |
| currentTxID = null; |
| finalURI = null; |
| } |
| |
| public void deleteBackup() { |
| if (backupFile != null) { |
| try { |
| // FileManager.getInstance().delete(backupFile); |
| new File(backupFile).delete(); |
| backupFile = null; |
| } catch (Throwable e) { |
| CommonPlugin.INSTANCE.log(e); |
| if (MultiFileSaveUtil.DEBUG) { |
| e.printStackTrace(); |
| } |
| } |
| } |
| } |
| |
| public boolean restore() { |
| File src = null, dest = null; |
| boolean moved = false; |
| if (backupFile != null) { |
| src = new File(backupFile); |
| dest = new File(getFinalURI().toFileString()); |
| } else { |
| moved = oldURI != null && !oldURI.equals(finalURI); |
| if (moved) { |
| File file = new File(getFinalURI().toFileString()); |
| dest = new File(oldURI.toFileString()); |
| moved = file.exists() && !dest.exists(); |
| if (moved) { |
| src = file; |
| } |
| } |
| } |
| if (src != null) { |
| if (dest.exists()) { |
| FileUtil.moveFile(dest,new File(getURI().toFileString())); |
| } |
| boolean success; |
| if (moved) { |
| success = MultiFileSaveUtil.move(this, src, dest); |
| // if(success) { |
| // MultiFileSaveUtil.updateURIMappings(this, null); |
| // } |
| } else { |
| // don't restore file if the source and destination are the same |
| // |
| success = src.lastModified() == dest.lastModified() && FileUtil.getSize(src) == FileUtil.getSize(dest); |
| if(!success) { |
| success = FileUtil.moveFile(src, dest); |
| } |
| } |
| if (!success) { |
| throw new MultiFileIOException(NLS.bind(PersistenceResources.restoreResourceError_msg, |
| FileManager.toFileString(getFinalURI()))); |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| URI getOldURI() { |
| return oldURI; |
| } |
| |
| boolean moveStarted() { |
| return oldURI != null && !oldURI.equals(getFinalURI()); |
| } |
| |
| boolean saveStarted() { |
| return currentTxID != null; |
| } |
| |
| private void refreshURIOfChildResources() { |
| // refresh resolve URIs in ResourceDescriptors of the child |
| // resources of this resource |
| // |
| HashMap<URI, ResourceDescriptor> oldURIToResourceDescriptorMap = null; |
| ResourceManager resMgr = MultiFileSaveUtil |
| .getResourceManager(this); |
| if (resMgr != null) { |
| oldURIToResourceDescriptorMap = new HashMap<URI, ResourceDescriptor>(); |
| for (Iterator<?> iter = resMgr.eAllContents(); iter |
| .hasNext();) { |
| Object obj = iter.next(); |
| if (obj instanceof ResourceDescriptor) { |
| ResourceDescriptor desc = ((ResourceDescriptor) obj); |
| oldURIToResourceDescriptorMap.put(desc |
| .getResolvedURI(), desc); |
| desc.clearResolvedURI(); |
| } |
| } |
| } |
| |
| // refresh URI of loaded child resources of this resource |
| // |
| if (oldURIToResourceDescriptorMap != null) { |
| // go thru the list of loaded resources in resource set |
| // to update the URI |
| // |
| for (Resource res : getResourceSet().getResources()) { |
| ResourceDescriptor desc = (ResourceDescriptor) oldURIToResourceDescriptorMap |
| .get(res.getURI()); |
| if (desc != null) { |
| res.setURI(desc.getResolvedURI()); |
| } |
| } |
| } |
| } |
| |
| public void commit() { |
| if (finalURI != null && !getContents().isEmpty()) { |
| File finalFile = new File(finalURI.toFileString()); |
| boolean wasMove = !oldURI.equals(finalURI); |
| if (wasMove) { |
| Object e = PersistenceUtil.getMethodElement(this); |
| if (e instanceof ContentDescription) { |
| if (finalFile.exists()) { |
| // name for finalFile is already taken |
| // try to get the next available name |
| // |
| finalURI = URI.createFileURI(MethodLibraryPersister |
| .getNextAvailableFileName(finalFile.getParent() |
| + File.separator, |
| (ContentDescription) e)); |
| finalFile = new File(finalURI.toFileString()); |
| } |
| } |
| } else { |
| // back up the file |
| // |
| String backup = getBackupFilePath(); |
| File bakFile = new File(backup); |
| |
| // trying to delete the old backup file if it exists |
| // |
| if (bakFile.exists()) { |
| bakFile.delete(); |
| } |
| |
| if (finalFile.exists()) { |
| // some CM provider like ClearCase renamed the versioned |
| // file it its repository as soon as user renamed the file |
| // in the workspace. To avoid this, use only regular rename |
| // routine of java.io.File instead of IResource routine |
| // |
| if (FileUtil.moveFile(finalFile, bakFile)) { |
| backupFile = backup; |
| } else { |
| String msg = NLS.bind( |
| PersistenceResources.renameError_msg, |
| finalFile, backup); |
| throw new MultiFileIOException(msg); |
| } |
| } |
| } |
| |
| // rename the resource file to the original name |
| // |
| File currentFile = new File(wasMove ? oldURI.toFileString() |
| : getURI().toFileString()); |
| boolean success = false; |
| Exception ex = null; |
| if (wasMove) { |
| success = MultiFileSaveUtil.move(this, currentFile, finalFile); |
| } else { |
| // some CM provider like ClearCase renamed the versioned file in |
| // its repository as soon as user renamed the file |
| // in the workspace. To avoid this, use only regular rename |
| // routine of java.io.File instead of IResource routine |
| // |
| try { |
| FileUtil.doMoveFile(currentFile, finalFile); |
| success = true; |
| } |
| catch(Exception e) { |
| ex = e; |
| } |
| } |
| if (!success) { |
| String msg = NLS.bind(PersistenceResources.renameError_msg, |
| currentFile, finalFile); |
| if(ex != null) { |
| msg = msg + ": " + (ex.getMessage() != null ? ex.getMessage() : ex.toString()); //$NON-NLS-1$ |
| } |
| throw new MultiFileIOException(msg); |
| } else { |
| if (wasMove) { |
| // refresh resolve URI of ResourceDescriptor of this |
| // resource |
| // |
| ResourceDescriptor resDesc = MultiFileSaveUtil |
| .getResourceDescriptor(this); |
| if (resDesc != null) { |
| resDesc.clearResolvedURI(); |
| resDesc.getResolvedURI(); |
| } |
| else { |
| if (MultiFileSaveUtil.DEBUG) { |
| MethodElement e = PersistenceUtil |
| .getMethodElement(this); |
| if (e != null |
| && !getLibraryPersister() |
| .hasOwnResourceWithoutReferrer(e)) { |
| String msg = "FATAL ERROR: no ResourceDescriptor found in parent resource for " + this; //$NON-NLS-1$ |
| CommonPlugin.INSTANCE.log(msg); |
| System.err.println(msg); |
| } |
| } |
| } |
| |
| refreshURIOfChildResources(); |
| } |
| |
| RefreshJob.getInstance().resourceSaved(this); |
| } |
| } |
| } |
| |
| public String getBackupFilePath() { |
| String backupFile = new StringBuffer(getTempDir()) |
| .append(File.separator) |
| .append(currentTxID) |
| .append("old").append(PersistenceUtil.getMethodElement(this).getGuid()).toString(); //$NON-NLS-1$ |
| return backupFile; |
| } |
| |
| /** |
| * @return the lastLoadTimeStamp |
| */ |
| public long getLastLoadTimeStamp() { |
| return lastLoadTimeStamp; |
| } |
| |
| static void clearDetachedEObjectToIDMap() { |
| DETACHED_EOBJECT_TO_ID_MAP.clear(); |
| } |
| |
| /** |
| * @param resDesc |
| */ |
| void setResourceDescriptor(ResourceDescriptor resDesc) { |
| resourceDescriptor = resDesc; |
| } |
| |
| public ResourceDescriptor getResourceDescriptor() { |
| return resourceDescriptor; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.epf.library.persistence.ILibraryResource#getLoadStamp() |
| */ |
| public long getLoadStamp() { |
| return getLastLoadTimeStamp(); |
| } |
| |
| public URI getProxyURI(EObject object) { |
| String guid = MultiFileSaveUtil.getGuid(object); |
| if (guid != null) { |
| ResourceDescriptor resourceDescriptor = this.resourceDescriptor != null ? this.resourceDescriptor : |
| MultiFileSaveUtil.getResourceDescriptor(this); |
| URI uri = resourceDescriptor != null ? MultiFileURIConverter |
| .createURI(resourceDescriptor.getId()) : getURI(); |
| return uri.appendFragment(guid); |
| } |
| return getURI().appendFragment(getID(object)); |
| } |
| |
| public void setTxID(String txID) { |
| setTempURI(txID); |
| } |
| |
| private ILibraryPersister getLibraryPersister() { |
| return ((MultiFileResourceSetImpl)resourceSet).getPersister(); |
| } |
| |
| private void handleSynFreeFlag(MethodElement e) { |
| if (e instanceof MethodPlugin || e instanceof ProcessComponent) { |
| MethodLibrary lib = UmaUtil.getMethodLibrary(e); |
| if (lib == null) { |
| lib = ((MultiFileResourceSetImpl)resourceSet).getMethodLibrary(); |
| } |
| if (lib != null) { |
| boolean isSynFree = UmaUtil.isSynFreeLibrary(lib); |
| if (isSynFree) { |
| if (e instanceof MethodPlugin) { |
| MethodPlugin p = (MethodPlugin) e; |
| if (! UmaUtil.isSynFreePlugin(p)) { |
| UmaUtil.setSynFreePlugin(p, true); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |