//------------------------------------------------------------------------------ // 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.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.emf.common.CommonPlugin; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.common.util.WrappedException; import org.eclipse.emf.ecore.EClass; 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.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.services.IFileBasedLibraryPersister; import org.eclipse.epf.uma.CapabilityPattern; import org.eclipse.epf.uma.ContentDescription; import org.eclipse.epf.uma.ContentElement; import org.eclipse.epf.uma.DeliveryProcess; import org.eclipse.epf.uma.DescribableElement; 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.MethodUnit; import org.eclipse.epf.uma.Process; import org.eclipse.epf.uma.ProcessComponent; import org.eclipse.epf.uma.UmaPackage; import org.eclipse.epf.uma.ecore.impl.MultiResourceEObject; import org.eclipse.epf.uma.util.UmaUtil; import org.eclipse.osgi.util.NLS; /** * File-based implementation for IMethodLibraryPersister * * @author Phong Nguyen Le * @since 1.0 */ public class MethodLibraryPersister implements IFileBasedLibraryPersister { private static class FolderInfo { EClass eClazz; boolean shared; private String name; /** * @param clazz * @param shared */ public FolderInfo(EClass clazz, boolean shared) { super(); eClazz = clazz; this.shared = shared; this.name = lowerAndPluralize(clazz.getName()); } } public static final MethodLibraryPersister INSTANCE = new MethodLibraryPersister(); // need to expose this, jxi public static final String RESOURCE_FOLDER = "resources"; //$NON-NLS-1$ private static final List folderInfos = new ArrayList(); static { folderInfos.add(new FolderInfo(UmaPackage.eINSTANCE.getGuidance(), false)); folderInfos.add(new FolderInfo(UmaPackage.eINSTANCE.getWorkProduct(), true)); folderInfos .add(new FolderInfo(UmaPackage.eINSTANCE.getActivity(), true)); } protected List warnings; public MethodLibraryPersister() { } /** * Returns the correct path (relative to the plugin) of the file of the * given content description or null if the given content does not be long * to any plugin. * * @param content * @return */ public static String getCorrectPath(ContentDescription content) { return getCorrectPath((DescribableElement) content.eContainer(), content); } private static String getCorrectPath(DescribableElement e, ContentDescription content) { if (e == null) return null; MethodPlugin plugin = UmaUtil.getMethodPlugin(e); if (plugin == null) { return null; } Resource resource = plugin.eResource(); URI uri = MultiFileSaveUtil.getFinalURI(resource); File pluginDir = new File(uri.toFileString()).getParentFile(); String folderPath = staticGetFolderPath(e.eClass()); String dir = new StringBuffer(pluginDir.getAbsolutePath()).append( File.separator).append(folderPath).append(File.separator) .toString(); return getNextAvailableFileName(dir, e, content); } /** * Gets next available file name for the given {@link MultiResourceEObject} in the given directory <code>dir</code> * * @param dir the directory path that must have a file separator at the end * @param requestedName * @param e * @return */ public static String getNextAvailableFileName(String dir, String requestedName, MultiResourceEObject e) { String currentFilename = null; File currentFile = null; MultiFileXMIResourceImpl resource = (MultiFileXMIResourceImpl) e .eDirectResource(); if (resource != null) { // keep existing file name during move if it is not taken yet. Don't // try to match the element's name // String path = ((MultiFileXMIResourceImpl) e.eResource()) .getFinalURI().toFileString(); currentFile = new File(path); currentFilename = currentFile.getName(); File file = new File(dir, currentFilename); if (!file.exists()) { // the element is being moved // return file.getAbsolutePath(); } } // element without a resource or path is already taken // String path = new StringBuffer(dir).append(requestedName).append( MultiFileSaveUtil.DEFAULT_FILE_EXTENSION).toString(); File file = new File(path); if(file.equals(currentFile)) { return path; } if ((currentFilename != null && currentFilename.equals(requestedName)) || file.exists()) { for (int i = 2; true; i++) { path = new StringBuffer(dir).append(requestedName).append(' ') .append(i).append( MultiFileSaveUtil.DEFAULT_FILE_EXTENSION) .toString(); if (!new File(path).exists()) { return path; } } } else { return path; } } static String getNextAvailableFileName(String dir, ContentDescription content) { return getNextAvailableFileName(dir, (DescribableElement) content .eContainer(), content); } private static String getNextAvailableFileName(String dir, DescribableElement e, ContentDescription content) { return getNextAvailableFileName(dir, e.getName(), (MultiResourceEObject) content); } private static String staticGetFolderPath(EClass eClazz) { int size = folderInfos.size(); FolderInfo info = null; for (int i = 0; i < size; i++) { FolderInfo folderInfo = (FolderInfo) folderInfos.get(i); if (folderInfo.eClazz.isSuperTypeOf(eClazz)) { info = folderInfo; } } if (info != null) { if (info.eClazz == eClazz || info.shared) { return info.name; } else { return new StringBuffer(info.name).append(File.separatorChar) .append(lowerAndPluralize(eClazz.getName())).toString(); } } else { return lowerAndPluralize(eClazz.getName()); } } public static String lowerAndPluralize(String name) { name = name.toLowerCase(); if (name.endsWith("children")) { //$NON-NLS-1$ return name; } else if (name.endsWith("child")) { //$NON-NLS-1$ return name + "ren"; //$NON-NLS-1$ } else if (name.endsWith("data")) { //$NON-NLS-1$ return name; } else if (name.endsWith("datum")) { //$NON-NLS-1$ return name.substring(0, name.length() - 2) + "a"; //$NON-NLS-1$ } else if (name.endsWith("by")) { //$NON-NLS-1$ return name + "s"; //$NON-NLS-1$ } else if (name.endsWith("y")) { //$NON-NLS-1$ return name.substring(0, name.length() - 1) + "ies"; //$NON-NLS-1$ } else if (name.endsWith("ex")) { //$NON-NLS-1$ return name.substring(0, name.length() - 2) + "ices"; //$NON-NLS-1$ } else if (name.endsWith("x")) { //$NON-NLS-1$ return name + "es"; //$NON-NLS-1$ } else if (name.endsWith("us")) { //$NON-NLS-1$ return name.substring(0, name.length() - 2) + "i"; //$NON-NLS-1$ } else if (name.endsWith("ss")) { //$NON-NLS-1$ return name + "es"; //$NON-NLS-1$ } else if (name.endsWith("s")) { //$NON-NLS-1$ return name; } else { return name + "s"; //$NON-NLS-1$ } } /** * Gets the virtual path to the resource folder of the given MethodElement object. * * @param e * @return * @see #getElementVirtualPath(MethodElement) */ public String geResourceVirtualPath(MethodElement e) { String folderPath = getElementVirtualPath(e); if (folderPath == null || folderPath.length() == 0) { return RESOURCE_FOLDER; } else { StringBuffer buffer = new StringBuffer(folderPath); if ( !folderPath.endsWith(File.separator) ) { buffer.append(File.separator); } buffer.append(RESOURCE_FOLDER); return buffer.toString(); } } /** * Gets the virtual path to the folder of the given MethodElement object. This path will have the following format: * <plugin_name>\folder_relative_path\ * * @param e * @return */ public String getElementVirtualPath(MethodElement e) { MethodPlugin plugin = UmaUtil.getMethodPlugin(e); if (plugin == null) { if (!(e instanceof MethodConfiguration || e instanceof MethodLibrary)) { // error: plugin element without a valid plugin set. This // problem needs to be fixed. // still see it from time to time, // for example, when lick on a capability pattern in // Configuration Explorer System.err .println("error in MethodLibraryPersister.getElementPath(): plugin element without a valid plugin. This problem needs to be fixed."); //$NON-NLS-1$ } return ""; //$NON-NLS-1$ } String folderPath = getFolderRelativePath(e); String pluginName = plugin.getName(); return (folderPath.length() == 0 ? pluginName + File.separator : new StringBuffer( pluginName).append(File.separatorChar).append(folderPath) .append(File.separatorChar).toString()); } /** * Gets the path relative to the library root directory to the * folder of the given MethodElement object. * * @param e * @return */ private String getRelativeElementPath(MethodElement e) { String folderPath = getFolderRelativePath(e); MethodPlugin plugin = UmaUtil.getMethodPlugin(e); if (plugin == null) { if ((e instanceof MethodConfiguration || e instanceof MethodLibrary)) { return folderPath; } else { // error: plugin element without a valid plugin set. This // problem needs to be fixed. // still see it from time to time, // for example, when lick on a capability pattern in // Configuration Explorer System.err .println("error in MethodLibraryPersister.getElementPath(): plugin element without a valid plugin. This problem needs to be fixed."); //$NON-NLS-1$ return ""; //$NON-NLS-1$ } } if (plugin.eContainer() == null) { // error: plugin without library set. This problem needs to be // fixed. // still see it from time to time System.err .println("error in MethodLibraryPersister.getElementPath(): plugin without library set. This problem needs to be fixed."); //$NON-NLS-1$ return ""; //$NON-NLS-1$ } String relPluginPath; if (plugin.eResource() != null) { Resource libRes = UmaUtil.getMethodLibrary(plugin).eResource(); if (libRes == plugin.eResource()) { // the plugin is not saved yet relPluginPath = plugin.getName(); } else { URI uri = MultiFileSaveUtil.getFinalURI(plugin.eResource()); URI libUri = MultiFileSaveUtil.getFinalURI(libRes); URI relUri = uri.deresolve(libUri); relPluginPath = relUri.trimSegments(1).toFileString(); } } else { // the library is not saved yet relPluginPath = plugin.getName(); } return (folderPath.length() == 0 ? relPluginPath + File.separator: new StringBuffer( relPluginPath).append(File.separatorChar).append(folderPath) .append(File.separatorChar).toString()); } public static void main(String[] args) { EClass eCls = UmaPackage.eINSTANCE.getTemplate(); System.out.println(eCls.getName()); } /** * Adjusts the location of the given resource and save all the resources * that have been changed as the result of this adjustment * * @param resource */ public void adjustLocation(Resource resource) { Set modifiedResources = new HashSet(); MultiFileSaveUtil.adjustLocation(resource, modifiedResources); // save the modified resources MultiFileResourceSetImpl resourceSet = (MultiFileResourceSetImpl) resource .getResourceSet(); for (Iterator iter = modifiedResources.iterator(); iter.hasNext();) { try { resourceSet.save((Resource) iter.next(), null); } catch (Exception e) { CommonPlugin.INSTANCE.log(e); } } } public void save(Resource resource) throws Exception { MultiFileResourceSetImpl resourceSet = (MultiFileResourceSetImpl) resource .getResourceSet(); resourceSet.save(resource, null); } protected void deleteFiles(MethodElement e, String path, ResourceSet resourceSet) { if (new File(path).isDirectory() && !e.eIsProxy()) { for (Iterator iter = resourceSet.getResources().iterator(); iter .hasNext();) { Resource res = (Resource) iter.next(); MethodElement me = PersistenceUtil.getMethodElement(res); if (me != null && UmaUtil.isContainedBy(me, e)) { res.unload(); iter.remove(); } } } try { FileManager.getInstance().deleteResource(path, null); } catch (CoreException ex) { CommonPlugin.INSTANCE.log(ex); throw new WrappedException(ex); } } /** * Deletes the files associated with the given MethodElement * * @param e */ protected void delete(MethodElement e, Set modifiedResources) { if (!UmaUtil.hasDirectResource(e)) { return; } MultiFileXMIResourceImpl resource = (MultiFileXMIResourceImpl) e .eResource(); MultiFileResourceSetImpl resourceSet = (MultiFileResourceSetImpl) resource .getResourceSet(); // Don't delete this resource's file if it still contains other // MethodElement for (Iterator iter = resource.getContents().iterator(); iter.hasNext();) { Object element = iter.next(); if (element instanceof MethodElement && element != e) { resourceSet.removeURIMappings(e, modifiedResources); resource.getContents().remove(e); modifiedResources.add(resource); return; } } String path; if (resourceSet.hasOwnFolder(e)) { // path is the directory of the MethodPlugin/ProcessComponent // path = new File(resource.getFinalURI().toFileString()).getParent(); // unload/remove all resources under the folder // Collection unloadedResources = new ArrayList(); do { unloadedResources.clear(); // collect all resources whose root element is contained by the // given element // for (Iterator iter = new ArrayList(resourceSet.getResources()) .iterator(); iter.hasNext();) { Resource res = (Resource) iter.next(); if (res.isLoaded()) { MethodElement me = PersistenceUtil .getMethodElement(res); if (me != null && UmaUtil.isContainedBy(me, e)) { unloadedResources.add(res); } } } for (Iterator iter = unloadedResources.iterator(); iter .hasNext();) { Resource res = (Resource) iter.next(); res.unload(); } resourceSet.getResources().removeAll(unloadedResources); } while (!unloadedResources.isEmpty()); } else { path = resource.getFinalURI().toFileString(); } try { resourceSet.cleanUp(resource, modifiedResources); } catch (Exception e1) { CommonPlugin.INSTANCE.log(e1); if (MultiFileSaveUtil.DEBUG) { e1.printStackTrace(); } } deleteFiles(e, path, resourceSet); } /** * @param e * @param objectsWithDirectResources */ private static void getObjectsWithDirectResources(EObject e, Collection objectsWithDirectResources) { if (UmaUtil.hasDirectResource(e)) { objectsWithDirectResources.add(e); } else { for (Iterator iter = e.eContents().iterator(); iter.hasNext();) { getObjectsWithDirectResources((EObject) iter.next(), objectsWithDirectResources); } } } /** * @see org.eclipse.epf.services.IFileBasedLibraryPersister#delete(org.eclipse.epf.uma.MethodElement) */ public void delete(MethodElement e) { // collect all elements with direct resources that are the given element // or its offstring ArrayList elements = new ArrayList(); getObjectsWithDirectResources(e, elements); deleteAndSave(elements); } private void deleteAndSave(ArrayList elements) { if (!elements.isEmpty()) { Set modifiedResources = new HashSet(); for (Iterator iter = elements.iterator(); iter.hasNext();) { delete((MethodElement) iter.next(), modifiedResources); } // save modified resources // for (Iterator iter = modifiedResources.iterator(); iter.hasNext();) { Resource resource = (Resource) iter.next(); try { save(resource); } catch (Exception ex) { throw new WrappedException(ex); } } } } /** * Gets the relative path of the folder that can store the content of the * given MethodElement. The path is relative to its plugin folder or library * folder if the element cannot be stored in a plugin. */ private static String staticGetFolderRelativePath(MethodElement e) { if (e instanceof MethodPlugin) { return ""; //$NON-NLS-1$ } else if (e instanceof ContentElement) { return staticGetFolderPath(e.eClass()); } else if (e instanceof MethodConfiguration) { return MultiFileSaveUtil.METHOD_CONFIGURATION_FOLDER_NAME; } MethodUnit unit = UmaUtil.getMethodUnit(e); if (unit instanceof ProcessComponent) { Process proc = ((ProcessComponent) unit).getProcess(); if (proc instanceof CapabilityPattern) { return MultiFileSaveUtil.CAPABILITY_PATTERN_PATH; } else if (proc instanceof DeliveryProcess) { return MultiFileSaveUtil.DELIVERY_PROCESS_PATH; } } else if (unit instanceof ContentDescription) { return staticGetFolderRelativePath((MethodElement) unit .eContainer()); } return ""; //$NON-NLS-1$ } public String getFolderRelativePath(MethodElement e) { return staticGetFolderRelativePath(e); } /* * (non-Javadoc) * * @see org.eclipse.epf.uma.util.IFileBasedLibraryPersister#getWarnings() */ public List getWarnings() { if (warnings == null) { warnings = new ArrayList(); } return warnings; } static class FailSafePersister extends MethodLibraryPersister implements FailSafeMethodLibraryPersister { private Map saveOptions; private TxRecord txRecord = new TxRecord() { /* * (non-Javadoc) * * @see org.eclipse.epf.persistence.TxRecord#clear() */ public void clear() { if (warnings != null && !warnings.isEmpty()) { // copy the warning to persister // FailSafePersister.this.warnings = Collections .unmodifiableList(warnings); } super.clear(); } }; private Map elementToInfoMapToDeleteFiles; public FailSafePersister() { saveOptions = new HashMap( MultiFileResourceSetImpl.DEFAULT_SAVE_OPTIONS); txRecord = new TxRecord(); saveOptions.put(MultiFileXMISaveImpl.TX_RECORD, txRecord); elementToInfoMapToDeleteFiles = new HashMap(); } /* * (non-Javadoc) * * @see org.eclipse.epf.persistence.MethodLibraryPersister#getWarnings() */ public List getWarnings() { if (txRecord.getTxID() == null) { return super.getWarnings(); } return txRecord.getWarnings(); } public Map getSaveOptions() { return saveOptions; } void checkMove(Resource resource) { // disallow new operation on resource which has started operation // that is not committed MultiFileXMIResourceImpl mfResource = (MultiFileXMIResourceImpl) resource; if (mfResource.txStarted()) { throw new MultiFileIOException(NLS.bind( PersistenceResources.moveResourceError_msg, resource)); } } /** * @see org.eclipse.epf.uma.persistence.MethodLibraryPersister#save(org.eclipse.emf.ecore.resource.Resource) */ public void save(Resource resource) throws Exception { if (resource != null) { if(resource.getResourceSet() instanceof MultiFileResourceSetImpl && resource instanceof MultiFileXMIResourceImpl) { MultiFileResourceSetImpl resourceSet = (MultiFileResourceSetImpl) resource .getResourceSet(); if (resourceSet == null) { return; } // update version info in library resource if needed // Resource libResourceToSave = null; MethodElement me = PersistenceUtil.getMethodElement(resource); if(me != null) { MethodLibrary lib = UmaUtil.getMethodLibrary(me); if(lib != null) { Resource libResource = lib.eResource(); if(libResource != null && libResource != resource && PersistenceUtil.checkToolVersion(libResource) != 0) { libResourceToSave = libResource; } } } if (MultiFileXMISaveImpl.checkModifyRequired(saveOptions)) { Collection<Resource> resources; if(libResourceToSave != null) { resources = new ArrayList<Resource>(); resources.add(resource); resources.add(libResourceToSave); } else { resources = Collections.singletonList(resource); } MultiFileSaveUtil.checkModify(resources); // check out-of-sync // MultiFileSaveUtil.checkOutOfSynch(resources, saveOptions); MultiFileSaveUtil.checkFilePathLength(resources); } resourceSet.save(resource, saveOptions); if(libResourceToSave != null) { resourceSet.save(libResourceToSave, saveOptions); } } else if(resource instanceof IFailSafeSavable) { IFailSafeSavable failSafeSavable = (IFailSafeSavable) resource; failSafeSavable.setTxID(txRecord.getTxID()); resource.save(saveOptions); txRecord.getResourcesToCommit().add(resource); } else { throw new IllegalAccessException("Resource must implement org.eclipse.epf.library.persistence.internal.IFailSafeSavable"); //$NON-NLS-1$ } } } /** * @see org.eclipse.epf.uma.persistence.MethodLibraryPersister#adjustLocation(org.eclipse.emf.ecore.resource.Resource) */ public void adjustLocation(Resource resource) { checkMove(resource); Set modifiedResources = new HashSet(); if (MultiFileSaveUtil.prepareAdjustLocation( (MultiFileXMIResourceImpl) resource, modifiedResources)) { txRecord.getResourcesToCommit().add(resource); HashSet resourcesToCheck = new HashSet(modifiedResources); resourcesToCheck.addAll(resourcesToCheck); MultiFileSaveUtil.checkModify(resourcesToCheck); if (!modifiedResources.isEmpty()) { MultiFileSaveUtil.checkOutOfSynch(modifiedResources, saveOptions); // save the modified resources for (Iterator iter = modifiedResources.iterator(); iter .hasNext();) { try { save((Resource) iter.next()); } catch (Exception e) { PersistencePlugin.getDefault().getLogger().logError(e); throw new MultiFileIOException(e.toString()); } } } } commit(); } public void adjustLocation(Collection resources) { if (resources == null || resources.isEmpty()) { return; } for (Iterator iter = resources.iterator(); iter.hasNext();) { checkMove((Resource) iter.next()); } Set modifiedResources = new HashSet(); HashSet resourcesToCheck = new HashSet(); for (Iterator iter = resources.iterator(); iter.hasNext();) { MultiFileXMIResourceImpl resource = (MultiFileXMIResourceImpl) iter .next(); if (MultiFileSaveUtil.prepareAdjustLocation( (MultiFileXMIResourceImpl) resource, modifiedResources)) { txRecord.getResourcesToCommit().add(resource); resourcesToCheck.add(resource); } } resourcesToCheck.addAll(modifiedResources); if(!resourcesToCheck.isEmpty()) { MultiFileSaveUtil.checkModify(resourcesToCheck); } if (!modifiedResources.isEmpty()) { MultiFileSaveUtil.checkOutOfSynch(modifiedResources, saveOptions); // save the modified resources for (Iterator iter = modifiedResources.iterator(); iter .hasNext();) { try { save((Resource) iter.next()); } catch (Exception e) { CommonPlugin.INSTANCE.log(e); throw new MultiFileIOException(e.toString()); } } } commit(); } /** * @see org.eclipse.epf.uma.persistence.MethodLibraryPersister#deleteFiles(org.eclipse.epf.uma.MethodElement, * java.lang.String, org.eclipse.emf.ecore.resource.ResourceSet) */ protected void deleteFiles(MethodElement e, String path, ResourceSet resourceSet) { // keep the info to really delete the files in commit() elementToInfoMapToDeleteFiles.put(e, new Object[] { path, resourceSet }); } private void superDeleteFiles(MethodElement e, String path, ResourceSet resourceSet) { super.deleteFiles(e, path, resourceSet); } /** * @see org.eclipse.epf.uma.util.IFileBasedLibraryPersister.FailSafeMethodLibraryPersister#commit() */ public void commit() { // save is done // call saveIsDone() on every saved file to rename it to the correct // name int size = txRecord.getResourcesToCommit().size(); for (int i = 0; i < size; i++) { ((IFailSafeSavable) txRecord.getResourcesToCommit() .get(i)).commit(); } // notify all commited resources that the transaction is done for (int i = 0; i < size; i++) { ((IFailSafeSavable) txRecord.getResourcesToCommit() .get(i)).txFinished(true); } // delete backup for (int i = 0; i < size; i++) { ((IFailSafeSavable) txRecord.getResourcesToCommit() .get(i)).deleteBackup(); } txRecord.clear(); // delete files of deleted elements // for (Iterator iter = elementToInfoMapToDeleteFiles.entrySet() .iterator(); iter.hasNext();) { Map.Entry entry = (Map.Entry) iter.next(); Object[] info = (Object[]) entry.getValue(); String path = (String) info[0]; try { superDeleteFiles((MethodElement) entry.getKey(), path, (ResourceSet) info[1]); } catch (Exception e) { if (e instanceof WrappedException) { e = ((WrappedException) e).exception(); } String msg = PersistenceResources.ErrMsg_CouldNotDelete; String otherMsg = null; if (e instanceof CoreException) { IStatus status = ((CoreException) e).getStatus(); if (status != null) { otherMsg = UmaUtil.getMessage(status); } } if (otherMsg == null) { otherMsg = ""; //$NON-NLS-1$ } msg = MessageFormat.format(msg, new Object[] { path, otherMsg }); e = new Exception(msg, e); getWarnings().add(e); CommonPlugin.INSTANCE.log(e); if (MultiFileSaveUtil.DEBUG) { e.printStackTrace(); } } } elementToInfoMapToDeleteFiles.clear(); } /** * @see org.eclipse.epf.uma.util.IFileBasedLibraryPersister.FailSafeMethodLibraryPersister#rollback() */ public void rollback() { if (!txRecord.getResourcesToCommit().isEmpty()) { try { int max = txRecord.getResourcesToCommit().size() - 1; ArrayList restoredResources = new ArrayList(); // Something went wrong, restore from backup for (int i = max; i > -1; i--) { IFailSafeSavable resource = (IFailSafeSavable) txRecord .getResourcesToCommit().get(i); if (resource.restore()) { restoredResources.add(resource); } } for (Iterator iter = restoredResources.iterator(); iter .hasNext();) { Resource resource = (Resource) iter .next(); resource.setModified(true); } // delete temp files for (int i = max; i > -1; i--) { Resource resource = (Resource) txRecord .getResourcesToCommit().get(i); if (((IFailSafeSavable)resource).hasTempURI()) { // uri keeps the path to temp file try { new File(resource.getURI().toFileString()) .delete(); } catch (Exception e) { CommonPlugin.INSTANCE.log(e); if (MultiFileSaveUtil.DEBUG) { e.printStackTrace(); } } } } // notify all commited resources that the transaction is // done for (int i = max; i > -1; i--) { ((IFailSafeSavable) txRecord .getResourcesToCommit().get(i)) .txFinished(false); } } catch (RuntimeException e) { CommonPlugin.INSTANCE.log(e); if (MultiFileSaveUtil.DEBUG) { e.printStackTrace(); } throw e; } } txRecord.clear(); } /** * @see org.eclipse.epf.services.IFileBasedLibraryPersister#getFailSafePersister() */ public FailSafeMethodLibraryPersister getFailSafePersister() { return this; } /** * @see org.eclipse.epf.uma.util.IFileBasedLibraryPersister.FailSafeMethodLibraryPersister#getCurrentTxID() */ public String getCurrentTxID() { return txRecord.getTxID(); } } FailSafePersister getFailSafePersister(Map options) { FailSafePersister persister = new FailSafePersister(); persister.saveOptions.putAll(options); // make sure that TX_RECORD still keeps the correct value persister.saveOptions.put(MultiFileXMISaveImpl.TX_RECORD, persister.txRecord); return persister; } /* * (non-Javadoc) * * @see org.eclipse.epf.uma.util.IFileBasedLibraryPersister#hasOwnFolder(java.lang.Object) */ public boolean hasOwnFolder(Object e) { return MultiFileSaveUtil.hasOwnFolder(e); } /* * (non-Javadoc) * * @see org.eclipse.epf.uma.util.IFileBasedLibraryPersister#hasOwnResource(java.lang.Object) */ public boolean hasOwnResource(Object e) { return MultiFileSaveUtil.hasOwnResource(e, MultiFileResourceSetImpl.DEFAULT_SAVE_SEPARATELY_CLASS_SET); } /** * @see org.eclipse.epf.services.IFileBasedLibraryPersister#getFailSafePersister() */ public FailSafeMethodLibraryPersister getFailSafePersister() { return new FailSafePersister(); } public static class NonFailSafePersister extends MethodLibraryPersister implements FailSafeMethodLibraryPersister { private Map saveOptions = new HashMap(); /** * @see org.eclipse.epf.uma.util.IFileBasedLibraryPersister.FailSafeMethodLibraryPersister#commit() */ public void commit() { // do nothing } /** * @see org.eclipse.epf.uma.util.IFileBasedLibraryPersister.FailSafeMethodLibraryPersister#rollback() */ public void rollback() { // do nothing } /** * @see org.eclipse.epf.uma.util.IFileBasedLibraryPersister.FailSafeMethodLibraryPersister#getCurrentTxID() */ public String getCurrentTxID() { return null; } /** * @see org.eclipse.epf.uma.util.IFileBasedLibraryPersister.FailSafeMethodLibraryPersister#adjustLocation(java.util.Collection) */ public void adjustLocation(Collection resources) { for (Iterator iter = resources.iterator(); iter.hasNext();) { adjustLocation((Resource) iter.next()); } } public Map getSaveOptions() { return saveOptions; } } private static final FailSafeMethodLibraryPersister nonFailSafePersister = new NonFailSafePersister(); /* * (non-Javadoc) * * @see org.eclipse.epf.uma.util.IFileBasedLibraryPersister#getFileExtension(java.lang.Object) */ public String getFileExtension(Object e) { return MultiFileSaveUtil.DEFAULT_FILE_EXTENSION; } /* (non-Javadoc) * @see org.eclipse.epf.uma.util.IFileBasedLibraryPersister#save(org.eclipse.epf.uma.MethodElement) */ public void save(MethodElement element) throws Exception { if(!hasOwnResourceWithoutReferrer(element)) { return; } MultiFileResourceSetImpl resourceSet = (MultiFileResourceSetImpl) UmaUtil.getMethodLibrary(element).eResource().getResourceSet(); Map options = resourceSet.getDefaultSaveOptions(); Resource res = ((InternalEObject)element).eDirectResource(); MultiFileXMIResourceImpl resource; if(res instanceof MultiFileXMIResourceImpl) { resource = (MultiFileXMIResourceImpl) res; resourceSet.save(resource, options); } else { URI uri = MultiFileSaveUtil.createURI(element, resourceSet); resource = MultiFileSaveUtil.save(resourceSet, element, uri, options, false); } resource.updateTimeStamps(); String str = (String) options.get(MultiFileXMISaveImpl.REFRESH_NEW_RESOURCE); if (str != null && Boolean.valueOf(str).booleanValue()) { // notify RefreshJob the this resource is saved so it will not be // reloaded after refreshing it // RefreshJob.getInstance().resourceSaved(resource); // refresh the newly created resource so it is in synch with the // workspace // FileManager.getInstance().refresh(resource); } } /* (non-Javadoc) * @see org.eclipse.epf.uma.util.IFileBasedLibraryPersister#hasOwnResourceWithoutReferrer(java.lang.Object) */ public boolean hasOwnResourceWithoutReferrer(Object e) { return e instanceof MethodConfiguration; } public File createMethodPluginFolder(String pluginName, MethodLibrary library) { File libDir = new File(library.eResource().getURI().toFileString()).getParentFile(); File pluginDir = new File(libDir, pluginName); if(!pluginDir.exists()) { if(!pluginDir.mkdirs()) { throw new MultiFileIOException(NLS.bind(PersistenceResources.cannot_create_dir_msg, pluginDir)); } } return pluginDir; } public File getDefaultMethodConfigurationFolder(MethodLibrary library) { return getDefaultMethodConfigurationFolder(library, true); } public File getDefaultMethodConfigurationFolder(MethodLibrary library, boolean create) { File libDir = new File(library.eResource().getURI().toFileString()).getParentFile(); File configDir = new File(libDir, MultiFileSaveUtil.METHOD_CONFIGURATION_FOLDER_NAME); if(configDir.exists()) { return configDir; } else if(create) { if(!configDir.mkdirs()) { throw new MultiFileIOException(NLS.bind(PersistenceResources.cannot_create_dir_msg, configDir)); } else { return configDir; } } return null; } public void setDefaultMethodConfigurationFolder(MethodLibrary library, File file) { // not allowed } public boolean isContainedBy(Resource resource, Resource containerResource) { MethodElement e = PersistenceUtil.getMethodElement(containerResource); if(hasOwnFolder(e)) { String path = FileManager.toFileString(resource.getURI()); String containerPath = FileManager.toFileString(containerResource.getURI()); if(path == null || containerPath == null) { return false; } return new Path(containerPath).removeLastSegments(1).isPrefixOf(new Path(path)); } return false; } public String getResourceFolderPath(MethodElement e) { String folderPath = getFolderAbsolutePath(e); return folderPath != null ? new File(folderPath, RESOURCE_FOLDER).getAbsolutePath() : RESOURCE_FOLDER; } public String getFolderAbsolutePath(MethodElement e) { MethodLibrary library = UmaUtil.getMethodLibrary(e); File libDir = null; if(library == null) { MethodPlugin plugin = UmaUtil.getMethodPlugin(e); Resource resource; if(plugin != null && (resource = ((InternalEObject) plugin).eDirectResource()) != null) { URI uri = MultiFileSaveUtil.getFinalURI(resource); libDir = new File(uri.toFileString()).getParentFile().getParentFile(); } } else { URI uri = MultiFileSaveUtil.getFinalURI(library.eResource()); libDir = new File(uri.toFileString()).getParentFile(); } if (libDir != null) { return new File(libDir, getRelativeElementPath(e)) .getAbsolutePath(); } else { return null; } } /* (non-Javadoc) * @see org.eclipse.epf.services.ILibraryPersister#delete(java.util.Collection) */ public void delete(Collection<MethodElement> elems) { ArrayList elements = new ArrayList(); for (Iterator<MethodElement> it = elems.iterator(); it.hasNext();) { getObjectsWithDirectResources(it.next(), elements); } deleteAndSave(elements); } public File getFile(Resource resource) { URI uri = MultiFileSaveUtil.getFinalURI(resource); return new File(FileManager.toFileString(uri)); } }