diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/core/RSECoreMessages.java b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/core/RSECoreMessages.java index e0e159dbc0f..15d27ce888b 100644 --- a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/core/RSECoreMessages.java +++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/core/RSECoreMessages.java @@ -12,6 +12,7 @@ * David McKnight (IBM) - [220309] [nls] Some GenericMessages and SubSystemResources should move from UI to Core * David McKnight (IBM) - [220547] [api][breaking] SimpleSystemMessage needs to specify a message id and some messages should be shared * David Dykstal (IBM) - [197167] adding notification and waiting for RSE model + * David Dykstal (IBM) - [189274] provide import and export operations for profiles ********************************************************************************/ package org.eclipse.rse.internal.core; @@ -48,6 +49,8 @@ public class RSECoreMessages extends NLS { public static String PropertyFileProvider_LoadingTaskName; public static String PropertyFileProvider_SavingTaskName; public static String PropertyFileProvider_UnexpectedException; + public static String RSEEnvelope_ExportNotSupported; + public static String RSEEnvelope_ModelNotExported; public static String RSEPersistenceManager_DeleteProfileJobName; public static String SaveRSEDOMJob_SavingProfileJobName; public static String SerializingProvider_UnexpectedException; diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/core/messages.properties b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/core/messages.properties index 17e4adcb6f0..e0318c0ebc3 100644 --- a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/core/messages.properties +++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/core/messages.properties @@ -13,6 +13,7 @@ # Xuan Chen (IBM) - fix check PII error # David McKnight (IBM) - [220309] [nls] Some GenericMessages and SubSystemResources should move from UI to Core # David McKnight (IBM) - [220547] [api][breaking] SimpleSystemMessage needs to specify a message id and some messages should be shared +# David Dykstal (IBM) - [189274] provide import and export operations for profiles ############################################################################### # NLS_MESSAGEFORMAT_VAR @@ -39,6 +40,8 @@ RESID_PROPERTYSET_REMOTE_SERVER_LAUNCHER=Remote Server Launcher RESID_PROPERTYSET_LAUNCHER_PROPERTIES=Launcher Properties # Persistence +RSEEnvelope_ExportNotSupported=The persistence provider does not support export. +RSEEnvelope_ModelNotExported=The persistence provider did not export the model. RSEPersistenceManager_DeleteProfileJobName=Delete RSE Profile Job PropertyFileProvider_SavingTaskName=Saving DOM PropertyFileProvider_UnexpectedException=Unexpected Exception diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/IRSEImportExportProvider.java b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/IRSEImportExportProvider.java new file mode 100644 index 00000000000..91ccf75798f --- /dev/null +++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/IRSEImportExportProvider.java @@ -0,0 +1,62 @@ +/********************************************************************************* + * Copyright (c) 2008 IBM Corporation. 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: + * David Dykstal (IBM) - initial contribution. + * David Dykstal (IBM) - [189274] provide import and export operations for profiles + *********************************************************************************/ + +package org.eclipse.rse.internal.persistence; + +import java.io.File; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.persistence.dom.RSEDOM; + +/** + * An import export provider is an add-in interface for a persistence provider. If the provider + * implements this interface then it may be used for import/export operations. + */ +public interface IRSEImportExportProvider { + + /** + * Exports an RSEDOM using this provider to a location named by the file parameter. + * The export is synchronous. + * @param folder the File object into which to export + * @param dom the DOM to export + * @param monitor the monitor to use for progress reporting and cancellation + * @return true if the export completed. + */ + public boolean exportRSEDOM(File folder, RSEDOM dom, IProgressMonitor monitor); + + /** + * Imports an RSEDOM using this provider from a location named by the file parameter. + * The import is synchronous. + * @param folder the File object from which to import. The DOM is located within this + * folder and the persistence provider must be able to find it. There must be only + * one DOM in this folder. + * @param monitor the monitor to use for progress reporting and cancellation + * @return the DOM that was imported or null if the import did not succeed. + */ + public RSEDOM importRSEDOM(File folder, IProgressMonitor monitor); + + /** + * Sets the provider identifier for this provider. This id is the one specified + * in the extension point that defined the provider, or the id that was specified for + * the provider when it was added to the manager. + * @param providerId The id for this provider. + */ + public void setId(String providerId); + + /** + * Gets the provider identifier for this provider. This id is the one specified + * in the extension point that defined the provider, or the id that was specified for + * the provider when it was added to the manager. + * @return The id for this provider. + */ + public String getId(); + +} diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/PFMetadataAnchor.java b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/PFMetadataAnchor.java index 8f84fe8a799..34ef97fe0d1 100644 --- a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/PFMetadataAnchor.java +++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/PFMetadataAnchor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 IBM Corporation and others. + * Copyright (c) 2007, 2008 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * David Dykstal (IBM) - [189274] provide import and export operations for profiles *******************************************************************************/ package org.eclipse.rse.internal.persistence; @@ -15,17 +16,21 @@ import java.io.File; import java.util.List; import java.util.Vector; -import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.rse.core.RSECorePlugin; import org.eclipse.rse.persistence.IRSEPersistenceProvider; import org.eclipse.rse.persistence.dom.RSEDOM; class PFMetadataAnchor implements PFPersistenceAnchor { + private File providerFolder = null; + + public PFMetadataAnchor(File providerFolder) { + this.providerFolder = providerFolder; + } + public IStatus deleteProfileLocation(String profileName, IProgressMonitor monitor) { IStatus result = Status.OK_STATUS; File profileFolder = getProfileFolder(profileName); @@ -43,7 +48,6 @@ class PFMetadataAnchor implements PFPersistenceAnchor { public String[] getProfileLocationNames() { List names = new Vector(10); - File providerFolder = getProviderFolder(); File[] profileCandidates = providerFolder.listFiles(); for (int i = 0; i < profileCandidates.length; i++) { File profileCandidate = profileCandidates[i]; @@ -67,22 +71,11 @@ class PFMetadataAnchor implements PFPersistenceAnchor { return new PFMetatdataJob(dom, provider); } - /** - * @return the folder that acts as the parent for profile folders. - */ - private File getProviderFolder() { - IPath statePath = RSECorePlugin.getDefault().getStateLocation(); - File stateFolder = new File(statePath.toOSString()); - File providerFolder = getFolder(stateFolder, "profiles"); //$NON-NLS-1$ - return providerFolder; - } - /** * Returns the File (directory) in which a profile is stored. * @return The folder that was created or found. */ private File getProfileFolder(String profileLocationName) { - File providerFolder = getProviderFolder(); File profileFolder = getFolder(providerFolder, profileLocationName); return profileFolder; } diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/PropertyFileProvider.java b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/PropertyFileProvider.java index f563f15800e..27e5bb04b0d 100644 --- a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/PropertyFileProvider.java +++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/PropertyFileProvider.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2006, 2007 IBM Corporation and others. All rights reserved. + * Copyright (c) 2006, 2008 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 @@ -13,11 +13,13 @@ * David Dykstal (IBM) - [177882] fixed escapeValue for garbling of CJK characters * Martin Oberhuber (Wind River) - [184095] Replace systemTypeName by IRSESystemType * David Dykstal (IBM) - [188863] fix job conflict problems for save jobs, ignore bad profiles on restore + * David Dykstal (IBM) - [189274] provide import and export operations for profiles ********************************************************************************/ package org.eclipse.rse.internal.persistence; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; @@ -35,6 +37,7 @@ import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.jobs.Job; @@ -51,7 +54,7 @@ import org.eclipse.rse.persistence.dom.RSEDOMNodeAttribute; * This is class is used to restore an RSE DOM from disk and import it into RSE. * It stores the DOM as a tree of folders and .properties files. */ -public class PropertyFileProvider implements IRSEPersistenceProvider { +public class PropertyFileProvider implements IRSEPersistenceProvider, IRSEImportExportProvider { private static final String NULL_VALUE_STRING = "null"; //$NON-NLS-1$ /* interesting character sets */ @@ -59,21 +62,28 @@ public class PropertyFileProvider implements IRSEPersistenceProvider { private static final String UPPER = "ABCDEFGHIJKLMNOPQRTSUVWXYZ"; //$NON-NLS-1$ /* properties */ + + /** + * anchor location - can be workspace or metadata + */ private static final String P_LOCATION = "location"; //$NON-NLS-1$ /* property values */ private static final String PV_LOCATION_WORKSPACE = "workspace"; //$NON-NLS-1$ private static final String PV_LOCATION_METADATA = "metadata"; //$NON-NLS-1$ - + + /* location names */ + private static final String LOC_PROFILES = "profiles"; //$NON-NLS-1$ private Pattern period = Pattern.compile("\\."); //$NON-NLS-1$ private Pattern suffixPattern = Pattern.compile("_(\\d+)$"); //$NON-NLS-1$ private Pattern unicodePattern = Pattern.compile("#(\\p{XDigit}+)#"); //$NON-NLS-1$ private Map typeQualifiers = getTypeQualifiers(); private Map saveJobs = new HashMap(); - private PFPersistenceAnchor anchor = null; +// private PFPersistenceAnchor anchor = null; private Properties properties = null; - + private String providerId = null; + /* (non-Javadoc) * @see org.eclipse.rse.persistence.IRSEPersistenceProvider#getSavedProfileNames() */ @@ -105,31 +115,38 @@ public class PropertyFileProvider implements IRSEPersistenceProvider { * @see org.eclipse.rse.persistence.IRSEPersistenceProvider#saveRSEDOM(org.eclipse.rse.persistence.dom.RSEDOM, org.eclipse.core.runtime.IProgressMonitor) */ public boolean saveRSEDOM(RSEDOM dom, IProgressMonitor monitor) { - boolean result = false; + boolean saved = false; synchronized (dom) { String profileLocationName = getLocationName(dom); - PFPersistenceLocation profileLocation = getAnchor().getProfileLocation(profileLocationName); - try { - int n = countNodes(dom); - monitor.beginTask(RSECoreMessages.PropertyFileProvider_SavingTaskName, n); - saveNode(dom, profileLocation, monitor); - monitor.done(); + PFPersistenceAnchor anchor = getAnchor(); + saved = save(dom, anchor, profileLocationName, monitor); + if (saved) { dom.markUpdated(); - result = true; - } catch (Exception e) { - logException(e); } } - return result; + return saved; } /* (non-Javadoc) * @see org.eclipse.rse.persistence.IRSEPersistenceProvider#loadRSEDOM(org.eclipse.rse.model.ISystemProfileManager, java.lang.String, org.eclipse.core.runtime.IProgressMonitor) */ public RSEDOM loadRSEDOM(String profileName, IProgressMonitor monitor) { - RSEDOM dom = null; String profileLocationName = getLocationName(PFConstants.AB_PROFILE, profileName); - PFPersistenceLocation location = getAnchor().getProfileLocation(profileLocationName); + PFPersistenceAnchor anchor = getAnchor(); + RSEDOM dom = load(anchor, profileLocationName, monitor); + return dom; + } + + /** + * Load a DOM from a named location within an anchor + * @param anchor the anchor that contained named locations for DOMs + * @param name the named location of that DOM + * @param monitor for progress reporting and cancelation + * @return the DOM what was loaded or null if the load failed + */ + private RSEDOM load(PFPersistenceAnchor anchor, String name, IProgressMonitor monitor) { + RSEDOM dom = null; + PFPersistenceLocation location = anchor.getProfileLocation(name); if (location.exists()) { int n = countLocations(location); monitor.beginTask(RSECoreMessages.PropertyFileProvider_LoadingTaskName, n); @@ -148,6 +165,7 @@ public class PropertyFileProvider implements IRSEPersistenceProvider { public Job getSaveJob(RSEDOM dom) { Job saveJob = (Job) saveJobs.get(dom); if (saveJob == null) { + PFPersistenceAnchor anchor = getAnchor(); saveJob = anchor.makeSaveJob(dom, this); saveJobs.put(dom, saveJob); } @@ -171,6 +189,40 @@ public class PropertyFileProvider implements IRSEPersistenceProvider { } } + /* (non-Javadoc) + * @see org.eclipse.rse.internal.persistence.IRSEImportExportProvider#exportRSEDOM(java.io.File, org.eclipse.rse.persistence.dom.RSEDOM, org.eclipse.core.runtime.IProgressMonitor) + */ + public boolean exportRSEDOM(File folder, RSEDOM dom, IProgressMonitor monitor) { + PFPersistenceAnchor anchor = new PFMetadataAnchor(folder); + String name = "DOM"; //$NON-NLS-1$ + boolean saved = save(dom, anchor, name, monitor); + return saved; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.internal.persistence.IRSEImportExportProvider#importRSEDOM(java.io.File, org.eclipse.core.runtime.IProgressMonitor) + */ + public RSEDOM importRSEDOM(File folder, IProgressMonitor monitor) { + PFPersistenceAnchor anchor = new PFMetadataAnchor(folder); + String name = "DOM"; //$NON-NLS-1$ + RSEDOM dom = load(anchor, name, monitor); + return dom; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.internal.persistence.IRSEImportExportProvider#setId(java.lang.String) + */ + public void setId(String providerId) { + this.providerId = providerId; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.internal.persistence.IRSEImportExportProvider#getId() + */ + public String getId() { + return providerId; + } + /** * Checks a profile name for validity. Currently all names are valid except for completely blank names. * @param profileName the name to check @@ -181,18 +233,56 @@ public class PropertyFileProvider implements IRSEPersistenceProvider { } private PFPersistenceAnchor getAnchor() { - if (anchor == null) { - String location = properties.getProperty(P_LOCATION); - if (location.equals(PV_LOCATION_WORKSPACE)) { - anchor = new PFWorkspaceAnchor(); - } else if (location.equals(PV_LOCATION_METADATA)) { - anchor = new PFMetadataAnchor(); - } else { - anchor = new PFMetadataAnchor(); - } + PFPersistenceAnchor anchor = null; + String location = properties.getProperty(P_LOCATION); + if (location.equals(PV_LOCATION_WORKSPACE)) { + anchor = new PFWorkspaceAnchor(); + } else if (location.equals(PV_LOCATION_METADATA)) { + File profilesFolder = getProfilesFolder(); + anchor = new PFMetadataAnchor(profilesFolder); + } else { + // if no explicit location is specified we assume the metadata location + File profilesFolder = getProfilesFolder(); + anchor = new PFMetadataAnchor(profilesFolder); } return anchor; } + + /** + * @return the folder that acts as the parent for profile folders. + */ + private File getProfilesFolder() { + IPath statePath = RSECorePlugin.getDefault().getStateLocation(); + File stateFolder = new File(statePath.toOSString()); + File profilesFolder = new File(stateFolder, LOC_PROFILES); + if (!profilesFolder.exists()) { + profilesFolder.mkdir(); + } + return profilesFolder; + } + + /** + * Save a DOM + * @param dom the DOM to save + * @param anchor the anchor in which DOMs may be saved + * @param name the name of the saved DOM within the anchor + * @param monitor for progress reporting and cancelation + * @return true if the DOM was saved to the named location within the anchor. + */ + private boolean save(RSEDOM dom, PFPersistenceAnchor anchor, String name, IProgressMonitor monitor) { + boolean saved = false; + PFPersistenceLocation profileLocation = anchor.getProfileLocation(name); + try { + int n = countNodes(dom); + monitor.beginTask(RSECoreMessages.PropertyFileProvider_SavingTaskName, n); + saveNode(dom, profileLocation, monitor); + monitor.done(); + saved = true; + } catch (Exception e) { + logException(e); + } + return saved; + } /** * Saves a node from the DOM to the file system. diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/RSEEnvelope.java b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/RSEEnvelope.java new file mode 100644 index 00000000000..55a4b4f892a --- /dev/null +++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/RSEEnvelope.java @@ -0,0 +1,490 @@ +/********************************************************************************* + * Copyright (c) 2008 IBM Corporation. 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: + * David Dykstal (IBM) - initial contribution. + * David Dykstal (IBM) - [189274] provide import and export operations for profiles + *********************************************************************************/ + +package org.eclipse.rse.internal.persistence; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.rse.core.RSECorePlugin; +import org.eclipse.rse.core.filters.ISystemFilterPool; +import org.eclipse.rse.core.filters.ISystemFilterPoolManager; +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.core.model.IPropertySet; +import org.eclipse.rse.core.model.ISystemProfile; +import org.eclipse.rse.core.model.ISystemRegistry; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.core.subsystems.ISubSystemConfiguration; +import org.eclipse.rse.internal.core.RSECoreMessages; +import org.eclipse.rse.internal.persistence.dom.RSEDOMExporter; +import org.eclipse.rse.internal.persistence.dom.RSEDOMImporter; +import org.eclipse.rse.persistence.IRSEPersistenceManager; +import org.eclipse.rse.persistence.IRSEPersistenceProvider; +import org.eclipse.rse.persistence.dom.IRSEDOMConstants; +import org.eclipse.rse.persistence.dom.RSEDOM; +import org.eclipse.rse.persistence.dom.RSEDOMNode; + +/** + * An envelope holds a version of a DOM that can be used for import and export of host, filterpool, and propertyset + * information. The envelope is capable of adding its contents to a profile (an import) and can also be used for generating a + * stream of its contents that can be used later for restore (an export). + */ +public class RSEEnvelope { + + private RSEDOM dom = null; + + /** + * Creates an import/export envelope. + */ + public RSEEnvelope() { + } + + /** + * Replaces the contents of this envelope with the contents found on the input stream. + * The format of the stream is determined by the persistence provider used to write the contents fo that stream. + * The stream is closed at the end of the operation. + * This operation is performed in the thread of the caller. + * If asynchronous operation is desired place this invocation inside a job. + * @param in the input stream which is read into the envelope. + * @param monitor a monitor used for tracking progress and cancelation. + * If the monitor is canceled this envelope will be empty. + * @throws IOException should one occur manipulating the stream. + */ + public void get(InputStream in, IProgressMonitor monitor) throws IOException { + File envelopeFolder = getTemporaryFolder(); + unzip(in, envelopeFolder); + String providerId = loadProviderId(envelopeFolder); + IRSEPersistenceManager manager = RSECorePlugin.getThePersistenceManager(); + IRSEPersistenceProvider provider = manager.getPersistenceProvider(providerId); + if (provider != null) { + if (provider instanceof IRSEImportExportProvider) { + IRSEImportExportProvider ieProvider = (IRSEImportExportProvider) provider; + dom = ieProvider.importRSEDOM(envelopeFolder, monitor); + } + } + deleteFileSystemObject(envelopeFolder); + } + + /** + * Exports the contents of the envelope to output stream. + * The format of the stream is determined by the persistence provider used. + * The id of the persistence provider is also recorded in the stream. + * The stream is closed at the end of the operation. + * This operation is performed in the same thread as the caller. + * If asynchronous operation is desired place this invocation inside a job. + * @param out the output stream into which the contents of this envelope will be written + * @param provider the persistence provider used to write the contents of this envelope + * @param monitor a monitor used for tracking progress and cancelation. If the monitor is canceled the + * receiving location is deleted. + * @throws CoreException containing a status describing the error, in particular this may be causes by + * an IOException while preparing the contents or if the provider does not support export. + */ + public void put(OutputStream out, IRSEPersistenceProvider provider, IProgressMonitor monitor) throws CoreException { + IStatus status = Status.OK_STATUS; + if (provider instanceof IRSEImportExportProvider) { + IRSEImportExportProvider exportProvider = (IRSEImportExportProvider) provider; + File envelopeFolder = getTemporaryFolder(); + boolean saved = exportProvider.exportRSEDOM(envelopeFolder, dom, monitor); + if (saved) { + status = saveProviderId(envelopeFolder, exportProvider); + if (status.isOK()) { + status = zip(envelopeFolder, out); + } + deleteFileSystemObject(envelopeFolder); + } else { + status = new Status(IStatus.ERROR, RSECorePlugin.PLUGIN_ID, RSECoreMessages.RSEEnvelope_ModelNotExported); + } + } else { + status = new Status(IStatus.ERROR, RSECorePlugin.PLUGIN_ID, RSECoreMessages.RSEEnvelope_ExportNotSupported); + } + try { + out.close(); + } catch (IOException e) { + status = makeStatus(e); + } + if (!status.isOK()) { + throw new CoreException(status); + } + } + + /** + * @return a file handle to a temporary directory + */ + private File getTemporaryFolder() { + IPath stateLocation = RSECorePlugin.getDefault().getStateLocation(); + File stateFolder = new File(stateLocation.toOSString()); + File envelopesFolder = new File(stateFolder, "envelopes"); //$NON-NLS-1$ + envelopesFolder.mkdir(); + List envelopeNames = Arrays.asList(envelopesFolder.list()); + String envelopeName = generateName(envelopeNames); + File envelopeFolder = new File(envelopesFolder, envelopeName); + envelopeFolder.mkdir(); + return envelopeFolder; + } + + /** + * Merges the contents of the envelope into the profile. + * @param profile the profile which is updated with the changes. The profile may be active or inactive. + */ + public void mergeWith(ISystemProfile profile) throws CoreException { + List hostNodes = new ArrayList(10); + List filterPoolNodes = new ArrayList(10); + List propertySetNodes = new ArrayList(10); + Map hostMap = new HashMap(10); // associates an original host name with a HostRecord + if (dom != null) { + RSEDOMNode[] children = dom.getChildren(); + for (int i = 0; i < children.length; i++) { + RSEDOMNode child = children[i]; + String nodeType = child.getType(); + if (nodeType.equals(IRSEDOMConstants.TYPE_HOST)) { + hostNodes.add(child); + } else if (nodeType.equals(IRSEDOMConstants.TYPE_FILTER_POOL)) { + filterPoolNodes.add(child); + } else if (nodeType.equals(IRSEDOMConstants.TYPE_PROPERTY_SET)) { + propertySetNodes.add(child); + } else { + throw new IllegalArgumentException("invalid dom node type"); //$NON-NLS-1$ + } + } + // create the hosts + for (Iterator z = hostNodes.iterator(); z.hasNext();) { + RSEDOMNode hostNode = (RSEDOMNode) z.next(); + String originalName = hostNode.getName(); + IHost host = mergeHost(profile, hostNode); + hostMap.put(originalName, host); + } + // create the filter pools + for (Iterator z = filterPoolNodes.iterator(); z.hasNext();) { + RSEDOMNode filterPoolNode = (RSEDOMNode) z.next(); + String name = filterPoolNode.getName(); + if (name.startsWith("CN-")) { //$NON-NLS-1$ + String hostName = name.substring(3); + IHost host = (IHost) hostMap.get(hostName); + if (host != null) { + mergeHostFilterPool(profile, host, filterPoolNode); + } else { + mergeFilterPool(profile, filterPoolNode); + } + } else { + mergeFilterPool(profile, filterPoolNode); + } + } + // TODO create the property sets + } + } + + private IHost mergeHost(ISystemProfile profile, RSEDOMNode hostNode) { + IHost host = null; + ISystemRegistry registry = RSECorePlugin.getTheSystemRegistry(); + String hostName = hostNode.getName(); + if (registry.getHost(profile, hostName) != null) { + int n = 0; + while (registry.getHost(profile, hostName) != null) { + n++; + hostName = hostName + "-" + n; //$NON-NLS-1$ + } + hostNode.setName(hostName); + } + RSEDOMImporter importer = RSEDOMImporter.getInstance(); + host = importer.restoreHost(profile, hostNode); + return host; + } + + private void mergeHostFilterPool(ISystemProfile profile, IHost host, RSEDOMNode filterPoolNode) { + String hostName = host.getAliasName(); + String filterPoolName = "CN-" + hostName; //$NON-NLS-1$ + filterPoolNode.setName(filterPoolName); + mergeFilterPool(profile, filterPoolNode); + } + + private ISystemFilterPool mergeFilterPool(ISystemProfile profile, RSEDOMNode filterPoolNode) { + ISystemFilterPool filterPool = getMatchingFilterPool(profile, filterPoolNode); + if (filterPool != null) { + String filterPoolName = filterPoolNode.getName(); + int n = 0; + while (filterPool != null) { + n++; + filterPoolName = filterPoolName + "-" + n; //$NON-NLS-1$ + filterPoolNode.setName(filterPoolName); + filterPool = getMatchingFilterPool(profile, filterPoolNode); + } + } + RSEDOMImporter importer = RSEDOMImporter.getInstance(); + filterPool = importer.restoreFilterPool(profile, filterPoolNode); + return filterPool; + } + + private ISystemFilterPool getMatchingFilterPool(ISystemProfile profile, RSEDOMNode filterPoolNode) { + ISystemRegistry registry = RSECorePlugin.getTheSystemRegistry(); + String filterPoolName = filterPoolNode.getName(); + String configurationId = filterPoolNode.getAttribute(IRSEDOMConstants.ATTRIBUTE_ID).getValue(); + ISubSystemConfiguration subsystemConfiguration = registry.getSubSystemConfiguration(configurationId); + ISystemFilterPoolManager manager = subsystemConfiguration.getFilterPoolManager(profile); + ISystemFilterPool filterPool = manager.getSystemFilterPool(filterPoolName); + return filterPool; + } + + private interface NodeAction { + abstract void run(); + } + + /** + * Adds a host to the envelope. + * If a host of the same name is already present in the envelope the new host will + * be renamed prior to adding it. + * @param host the host to be added to the envelope + */ + public void add(final IHost host) { + // find and add the host-unique filter pools + ISubSystem[] subsystems = host.getSubSystems(); + for (int i = 0; i < subsystems.length; i++) { + ISubSystem subsystem = subsystems[i]; + ISystemFilterPool pool = subsystem.getUniqueOwningSystemFilterPool(false); + if (pool != null) { + add(pool); + } + } + // add the host + String type = IRSEDOMConstants.TYPE_HOST; + String name = host.getName(); + NodeAction action = new NodeAction() { + public void run() { + RSEDOMExporter.getInstance().createNode(dom, host, true); + } + }; + addNode(type, name, action); + } + + /** + * Adds a filter pool to the envelope. + * If a filter pool of the same name is already present in the envelope the new filter pool will + * be renamed prior to adding it. + * @param pool the filter pool to be added to the envelope + */ + public void add(final ISystemFilterPool pool) { + // add the pool + String type = IRSEDOMConstants.TYPE_FILTER_POOL; + String name = pool.getName(); + NodeAction action = new NodeAction() { + public void run() { + RSEDOMExporter.getInstance().createNode(dom, pool, true); + } + }; + addNode(type, name, action); + } + + /** + * Adds a property set to the envelope. + * If a property set of the same name is already present in the envelope the new property set will + * be renamed prior to adding it. + * @param propertySet the property set to be added to the envelope + */ + public void add(final IPropertySet propertySet) { + // add the property set + String type = IRSEDOMConstants.TYPE_FILTER_POOL; + String name = propertySet.getName(); + NodeAction action = new NodeAction() { + public void run() { + RSEDOMExporter.getInstance().createNode(dom, propertySet, true); + } + }; + addNode(type, name, action); + } + + private IStatus saveProviderId(File parent, IRSEImportExportProvider provider) { + IStatus status = Status.OK_STATUS; + String providerId = provider.getId(); + File idFile = new File(parent, "provider.id"); //$NON-NLS-1$ + try { + OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(idFile)); + out.write(providerId); + out.close(); + } catch (IOException e) { + status = makeStatus(e); + } + return status; + } + + private String loadProviderId(File parent) { + String providerId = null; + File idFile = new File(parent, "provider.id"); //$NON-NLS-1$ + try { + BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(idFile))); + providerId = in.readLine(); + in.close(); + } catch (IOException e) { + } + return providerId; + } + + private void addNode(String type, String name, NodeAction action) { + ensureDOM(); + RSEDOMNode existingNode = dom.getChild(type, name); + if (existingNode != null) { + dom.removeChild(existingNode); + } + action.run(); + } + + private void ensureDOM() { + if (dom == null) { + initialize(); + } + } + + private void initialize() { + dom = new RSEDOM("dom"); //$NON-NLS-1$ + } + + private String generateName(List usedNames) { + String prefix = "env_"; //$NON-NLS-1$ + int n = 0; + String name = prefix + n; + while (usedNames.contains(name)) { + n += 1; + name = prefix + n; + } + return name; + } + + private IStatus zip(File source, OutputStream target) { + IStatus status = Status.OK_STATUS; + try { + ZipOutputStream out = new ZipOutputStream(target); + zipEntry(out, source, ""); //$NON-NLS-1$ + out.close(); + } catch (IOException e) { + status = makeStatus(e); + } + return status; + } + + private void zipEntry(ZipOutputStream out, File file, String entryName) { + if (file.isDirectory()) { + zipDirectoryEntry(out, file, entryName); + } else { + zipFileEntry(out, file, entryName); + } + } + + private void zipDirectoryEntry(ZipOutputStream out, File file, String entryName) { + String fileName = file.getName(); + if (!(fileName.equals(".") || fileName.equals(".."))) { //$NON-NLS-1$ //$NON-NLS-2$ + if (entryName.length() > 0) { + try { + ZipEntry entry = new ZipEntry(entryName + "/"); //$NON-NLS-1$ + out.putNextEntry(entry); + out.closeEntry(); + } catch (IOException e) { + e.printStackTrace(); + } + } + File[] files = file.listFiles(); + for (int i = 0; i < files.length; i++) { + File child = files[i]; + String childName = child.getName(); + String childEntryName = entryName + "/" + childName; //$NON-NLS-1$ + zipEntry(out, child, childEntryName); + } + } + } + + private void zipFileEntry(ZipOutputStream out, File file, String entryName) { + try { + ZipEntry entry = new ZipEntry(entryName); + out.putNextEntry(entry); + byte[] buffer = new byte[4096]; + FileInputStream in = new FileInputStream(file); + for (int n = in.read(buffer); n >= 0; n = in.read(buffer)) { + out.write(buffer, 0, n); + } + in.close(); + out.closeEntry(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private IStatus unzip(InputStream in, File root) { + IStatus status = Status.OK_STATUS; + try { + ZipInputStream inZip = new ZipInputStream(in); + ZipEntry entry = inZip.getNextEntry(); + while (entry != null) { + String name = entry.getName(); + File target = new File(root, name); + if (entry.isDirectory()) { + target.mkdir(); + } else { + byte[] buffer = new byte[4096]; + FileOutputStream out = new FileOutputStream(target); + for (int n = inZip.read(buffer); n >= 0; n = inZip.read(buffer)) { + out.write(buffer, 0, n); + } + out.close(); + } + entry = inZip.getNextEntry(); + } + inZip.close(); + } catch (FileNotFoundException e) { + status = makeStatus(e); + } catch (IOException e) { + status = makeStatus(e); + } + return status; + } + + private IStatus deleteFileSystemObject(File file) { + IStatus status = Status.OK_STATUS; + String fileName = file.getName(); + if (!(fileName.equals(".") || fileName.equals(".."))) { //$NON-NLS-1$ //$NON-NLS-2$ + if (file.exists()) { + if (file.isDirectory()) { + File[] files = file.listFiles(); + for (int i = 0; i < files.length; i++) { + File child = files[i]; + deleteFileSystemObject(child); + } + } + file.delete(); + } + } + return status; + } + + private IStatus makeStatus(Exception e) { + IStatus status = new Status(IStatus.ERROR, RSECorePlugin.PLUGIN_ID, "Unexpected Exception", e); //$NON-NLS-1$ + return status; + } + +} diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/RSEPersistenceManager.java b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/RSEPersistenceManager.java index c9a8ba55304..744817c127b 100644 --- a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/RSEPersistenceManager.java +++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/RSEPersistenceManager.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2006, 2007 IBM Corporation and others. All rights reserved. + * Copyright (c) 2006, 2008 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 @@ -17,6 +17,7 @@ * Martin Oberhuber (Wind River) - [175680] Deprecate obsolete ISystemRegistry methods * Martin Oberhuber (Wind River) - [196919] Fix deadlock with workspace operations * Martin Oberhuber (Wind River) - [202416] Protect against NPEs when importing DOM + * David Dykstal (IBM) - [189274] provide import and export operations for profiles ********************************************************************************/ package org.eclipse.rse.internal.persistence; @@ -105,6 +106,10 @@ public class RSEPersistenceManager implements IRSEPersistenceManager { */ public void registerPersistenceProvider(String id, IRSEPersistenceProvider provider) { ProviderRecord pr = getProviderRecord(id); + if (provider instanceof IRSEImportExportProvider) { + IRSEImportExportProvider ieProvider = (IRSEImportExportProvider) provider; + ieProvider.setId(id); + } pr.provider = provider; loadedProviders.put(provider, id); } @@ -117,7 +122,10 @@ public class RSEPersistenceManager implements IRSEPersistenceManager { */ public IRSEPersistenceProvider getPersistenceProvider(String id) { ProviderRecord pr = getProviderRecord(id); - loadProvider(pr); + if (pr.provider == null) { + IRSEPersistenceProvider provider = loadProvider(pr.configurationElement); + registerPersistenceProvider(id, provider); + } return pr.provider; } @@ -306,32 +314,30 @@ public class RSEPersistenceManager implements IRSEPersistenceManager { } /** - * Loads a provider given a provider record. If the provider has already been loaded - * it will not load it again. After loading, the provider will be initialized with any + * Loads a provider given a configuration element. + * After loading, the provider will be initialized with any * properties found in the extension. - * @param pr the provider record containing the configuration element describing the provider + * @param configurationElement the element that contains the class and properties to load * @return the provider */ - private IRSEPersistenceProvider loadProvider(ProviderRecord pr) { - if (pr.provider == null) { - try { - pr.provider = (IRSEPersistenceProvider) pr.configurationElement.createExecutableExtension("class"); //$NON-NLS-1$ - loadedProviders.put(pr.provider, pr.providerId); - Properties properties = new Properties(); - IConfigurationElement[] children = pr.configurationElement.getChildren("property"); //$NON-NLS-1$ - for (int i = 0; i < children.length; i++) { - IConfigurationElement child = children[i]; - String name = child.getAttribute("name"); //$NON-NLS-1$ - String value = child.getAttribute("value"); //$NON-NLS-1$ - properties.put(name, value); - } - pr.provider.setProperties(properties); - } catch (CoreException e) { - Logger logger = RSECorePlugin.getDefault().getLogger(); - logger.logError("Exception loading persistence provider", e); //$NON-NLS-1$ + private IRSEPersistenceProvider loadProvider(IConfigurationElement configurationElement) { + IRSEPersistenceProvider provider = null; + try { + provider = (IRSEPersistenceProvider) configurationElement.createExecutableExtension("class"); //$NON-NLS-1$ + Properties properties = new Properties(); + IConfigurationElement[] children = configurationElement.getChildren("property"); //$NON-NLS-1$ + for (int i = 0; i < children.length; i++) { + IConfigurationElement child = children[i]; + String name = child.getAttribute("name"); //$NON-NLS-1$ + String value = child.getAttribute("value"); //$NON-NLS-1$ + properties.put(name, value); } + provider.setProperties(properties); + } catch (CoreException e) { + Logger logger = RSECorePlugin.getDefault().getLogger(); + logger.logError("Exception loading persistence provider", e); //$NON-NLS-1$ } - return pr.provider; + return provider; } /** diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/dom/RSEDOMExporter.java b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/dom/RSEDOMExporter.java index 29d58db5845..a86ea2c99dc 100644 --- a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/dom/RSEDOMExporter.java +++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/internal/persistence/dom/RSEDOMExporter.java @@ -17,6 +17,7 @@ * Kevin Doyle (IBM) - [163883] Multiple filter strings are disabled * Kevin Doyle (IBM) - [197199] Renaming a Profile doesn't cause a save * David McKnight (IBM) - [217715] [api] RSE property sets should support nested property sets + * David Dykstal (IBM) - [189274] provide import and export operations for profiles *******************************************************************************/ package org.eclipse.rse.internal.persistence.dom; @@ -171,27 +172,39 @@ public class RSEDOMExporter implements IRSEDOMExporter { RSEDOMNode[] result = new RSEDOMNode[propertySets.length]; for (int i = 0; i < propertySets.length; i++) { IPropertySet set = propertySets[i]; - RSEDOMNode propertySetNode = new RSEDOMNode(parent, IRSEDOMConstants.TYPE_PROPERTY_SET, set.getName()); - propertySetNode.addAttribute(IRSEDOMConstants.ATTRIBUTE_DESCRIPTION, set.getDescription()); - String[] keys = set.getPropertyKeys(); - for (int k = 0; k < keys.length; k++) { - String key = keys[k]; - String value = set.getPropertyValue(key); - IPropertyType type = set.getPropertyType(key); - RSEDOMNode propertyNode = new RSEDOMNode(propertySetNode, IRSEDOMConstants.TYPE_PROPERTY, key); - propertyNode.addAttribute(IRSEDOMConstants.ATTRIBUTE_TYPE, type.toString()); - propertyNode.addAttribute(IRSEDOMConstants.ATTRIBUTE_VALUE, value); - - } + RSEDOMNode propertySetNode = createNode(parent, set, clean); result[i] = propertySetNode; - // persist nested property sets of property set - if (set instanceof IRSEModelObject){ - createPropertySetNodes(propertySetNode, (IRSEModelObject)set, clean); - } } return result; } + /** + * Creates a DOM node for a property set + * @param parent the owning parent of the node + * @param set the property set from which to create a node + * @param clean true if we are creating, false if we are merging + * @return the DOM node representing the property set + */ + public RSEDOMNode createNode(RSEDOMNode parent, IPropertySet set, boolean clean) { + RSEDOMNode propertySetNode = new RSEDOMNode(parent, IRSEDOMConstants.TYPE_PROPERTY_SET, set.getName()); + propertySetNode.addAttribute(IRSEDOMConstants.ATTRIBUTE_DESCRIPTION, set.getDescription()); + String[] keys = set.getPropertyKeys(); + for (int k = 0; k < keys.length; k++) { + String key = keys[k]; + String value = set.getPropertyValue(key); + IPropertyType type = set.getPropertyType(key); + RSEDOMNode propertyNode = new RSEDOMNode(propertySetNode, IRSEDOMConstants.TYPE_PROPERTY, key); + propertyNode.addAttribute(IRSEDOMConstants.ATTRIBUTE_TYPE, type.toString()); + propertyNode.addAttribute(IRSEDOMConstants.ATTRIBUTE_VALUE, value); + + } + // persist nested property sets of property set + if (set instanceof IRSEModelObject){ + createPropertySetNodes(propertySetNode, (IRSEModelObject)set, clean); + } + return propertySetNode; + } + /** * Create a DOM node representing a filter pool * @param parent the parent DOM node @@ -447,7 +460,7 @@ public class RSEDOMExporter implements IRSEDOMExporter { private RSEDOMNode findOrCreateNode(RSEDOMNode parent, String type, IRSEModelObject modelObject, boolean clean) { RSEDOMNode node = null; String name = modelObject.getName(); - if (!clean) { + if (!clean && parent != null) { node = parent.getChild(type, name); if (node != null && modelObject.isDirty()) { node.clearAttributes(); diff --git a/rse/tests/org.eclipse.rse.tests/META-INF/MANIFEST.MF b/rse/tests/org.eclipse.rse.tests/META-INF/MANIFEST.MF index 868de1a25d2..890795b7feb 100644 --- a/rse/tests/org.eclipse.rse.tests/META-INF/MANIFEST.MF +++ b/rse/tests/org.eclipse.rse.tests/META-INF/MANIFEST.MF @@ -9,20 +9,20 @@ Bundle-Localization: plugin Require-Bundle: org.junit, org.eclipse.core.runtime, org.eclipse.core.resources, + org.eclipse.core.filesystem, org.eclipse.ui, + org.eclipse.ui.views, org.eclipse.rse.core;bundle-version="[3.0.0,4.0.0)", org.eclipse.rse.ui;bundle-version="[3.0.0,4.0.0)", org.eclipse.rse.subsystems.files.core;bundle-version="[3.0.0,4.0.0)", org.eclipse.rse.subsystems.processes.core;bundle-version="[3.0.0,4.0.0)", org.eclipse.rse.subsystems.shells.core;bundle-version="[3.0.0,4.0.0)", - org.eclipse.rse.tests.framework;bundle-version="[2.0.0,3.0.0)", - org.eclipse.ui.views, org.eclipse.rse.services;bundle-version="[3.0.0,4.0.0)", org.eclipse.rse.services.files.ftp;bundle-version="[3.0.0,4.0.0)", org.eclipse.rse.subsystems.files.ftp;bundle-version="[3.0.0,4.0.0)", - org.eclipse.core.filesystem, org.eclipse.rse.files.ui, - org.eclipse.rse.efs + org.eclipse.rse.efs, + org.eclipse.rse.tests.framework;bundle-version="[2.0.0,3.0.0)" Bundle-ActivationPolicy: lazy Eclipse-LazyStart: true Bundle-RequiredExecutionEnvironment: J2SE-1.4 diff --git a/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/persistence/ExportImportTest.java b/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/persistence/ExportImportTest.java new file mode 100644 index 00000000000..4a5a2b18ed6 --- /dev/null +++ b/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/persistence/ExportImportTest.java @@ -0,0 +1,190 @@ +/********************************************************************************* + * Copyright (c) 2008 IBM Corporation. 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: + * David Dykstal (IBM) - initial contribution. + * David Dykstal (IBM) - [189274] provide import and export operations for profiles + *********************************************************************************/ + +package org.eclipse.rse.tests.persistence; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.rse.core.IRSESystemType; +import org.eclipse.rse.core.RSECorePlugin; +import org.eclipse.rse.core.filters.ISystemFilter; +import org.eclipse.rse.core.filters.ISystemFilterPool; +import org.eclipse.rse.core.filters.ISystemFilterPoolManager; +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.core.model.ISystemProfile; +import org.eclipse.rse.core.model.ISystemProfileManager; +import org.eclipse.rse.core.model.ISystemRegistry; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.core.subsystems.ISubSystemConfiguration; +import org.eclipse.rse.internal.persistence.RSEEnvelope; +import org.eclipse.rse.persistence.IRSEPersistenceManager; +import org.eclipse.rse.persistence.IRSEPersistenceProvider; +import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileSubSystem; +import org.eclipse.rse.tests.core.RSECoreTestCase; + +/** + * + */ +public class ExportImportTest extends RSECoreTestCase { + + ISystemProfile sourceProfile = null; + ISystemRegistry registry = null; + IRSEPersistenceManager manager = null; + ISubSystemConfiguration configuration = null; + + public ExportImportTest(String name) { + super(name); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.tests.core.RSECoreTestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + // get the registry and persistence provider + manager = RSECorePlugin.getThePersistenceManager(); + registry = RSECorePlugin.getTheSystemRegistry(); + // create the first profile and populate it + ISystemProfileManager profileManager = registry.getSystemProfileManager(); + sourceProfile = profileManager.createSystemProfile("profile1", true); + // populate profile1 with a connection (host1) + IRSESystemType systemType = RSECorePlugin.getTheCoreRegistry().getSystemTypeById(IRSESystemType.SYSTEMTYPE_UNIX_ID); + IHost host1 = registry.createHost(sourceProfile.getName(), systemType, "host1", "localhost", "host1", true); + // find its file subsystem + ISubSystem[] subsystems = registry.getSubsystems(host1, IRemoteFileSubSystem.class); + ISubSystem host1FileSubsystem = subsystems[0]; + // create a connection-private filter (hostFilter1) + String[] filterStrings = new String[] { "*.txt" }; + ISystemFilterPool host1FilterPool = host1FileSubsystem.getUniqueOwningSystemFilterPool(true); + host1FilterPool.createSystemFilter("hostFilter1", filterStrings); + // create a connection-private filter (hostFilter2) + filterStrings = new String[] { "*.c" }; + host1FilterPool.createSystemFilter("hostFilter2", filterStrings); + // create a shared filter pool + configuration = host1FileSubsystem.getSubSystemConfiguration(); + ISystemFilterPoolManager filterPoolManager = configuration.getFilterPoolManager(sourceProfile, true); + ISystemFilterPool sharedFilterPool = filterPoolManager.createSystemFilterPool("sharedFilterPool", true); + // create a shared filter (sharedFilter) + filterStrings = new String[] { "*.java", "*.txt", "*.c" }; + sharedFilterPool.createSystemFilter("sharedFilter", filterStrings); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.tests.core.RSECoreTestCase#tearDown() + */ + protected void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Export a single filter pool and import it into an empty profile. + */ + public void testFilterPool1() { + //-test-author-:DavidDykstal + try { + // find the provider + IRSEPersistenceProvider persistenceProvider = manager.getPersistenceProvider("org.eclipse.rse.persistence.PropertyFileProvider"); + // find a shared filter pool + ISystemFilterPoolManager fpm = configuration.getFilterPoolManager(sourceProfile); + ISystemFilterPool fp = fpm.getSystemFilterPool("sharedFilterPool"); + // export the filter pool + RSEEnvelope envelope = new RSEEnvelope(); + envelope.add(fp); + IProgressMonitor monitor = new NullProgressMonitor(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + envelope.put(out, persistenceProvider, monitor); + // create an empty profile + ISystemProfile targetProfile = registry.createSystemProfile("profileFilterPool1", true); + // import into the profile + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + monitor = new NullProgressMonitor(); + envelope.get(in, monitor); + envelope.mergeWith(targetProfile); + // verify the contents + assertEquals(0, registry.getHostCount(targetProfile)); + fpm = configuration.getFilterPoolManager(targetProfile); + assertNotNull(fpm); + ISystemFilterPool[] pools = fpm.getSystemFilterPools(); + assertEquals(1, pools.length); + fp = pools[0]; + assertNotNull(fp); + assertEquals("sharedFilterPool", fp.getName()); + ISystemFilter[] filters = fp.getFilters(); + assertEquals(1, filters.length); + ISystemFilter filter = filters[0]; + assertEquals("sharedFilter", filter.getName()); + String[] strings = filter.getFilterStrings(); + assertEquals(3, strings.length); + assertEquals("*.java", strings[0]); + assertEquals("*.txt", strings[1]); + assertEquals("*.c", strings[2]); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Export a single host and import it into an empty profile. + */ + public void testHost1() { + //-test-author-:DavidDykstal + try { + // find the provider + IRSEPersistenceProvider persistenceProvider = manager.getPersistenceProvider("org.eclipse.rse.persistence.PropertyFileProvider"); + // create an empty profile + ISystemProfile targetProfile = registry.createSystemProfile("profile2", true); + // export a host to a stream this export all connection private pools as well. + IHost host1 = registry.getHost(sourceProfile, "host1"); + RSEEnvelope envelope = new RSEEnvelope(); + envelope.add(host1); + IProgressMonitor monitor = new NullProgressMonitor(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + envelope.put(out, persistenceProvider, monitor); + // import from the newly created stream + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + monitor = new NullProgressMonitor(); + envelope.get(in, monitor); + envelope.mergeWith(targetProfile); + // verify the contents + IHost[] hosts = targetProfile.getHosts(); + assertEquals(1, hosts.length); + IHost host = hosts[0]; + assertEquals("host1", host.getAliasName()); + ISubSystem[] subsystems = registry.getSubsystems(host, IRemoteFileSubSystem.class); + assertEquals(1, subsystems.length); + ISubSystem subsystem = subsystems[0]; + ISystemFilterPool fp = subsystem.getUniqueOwningSystemFilterPool(false); + assertNotNull(fp); + ISystemFilter[] filters = fp.getFilters(); + assertEquals(2, filters.length); + ISystemFilter filter = filters[0]; + assertEquals("hostFilter1", filter.getName()); + String[] strings = filter.getFilterStrings(); + assertEquals(1, strings.length); + assertEquals("*.txt", strings[0]); + filter = filters[1]; + assertEquals("hostFilter2", filter.getName()); + strings = filter.getFilterStrings(); + assertEquals(1, strings.length); + assertEquals("*.c", strings[0]); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void testPropertySet() { + //-test-author-:DavidDykstal + } + +} diff --git a/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/persistence/MigrationTest.java b/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/persistence/MigrationTest.java new file mode 100644 index 00000000000..7b61e7c41b2 --- /dev/null +++ b/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/persistence/MigrationTest.java @@ -0,0 +1,34 @@ +/********************************************************************************* + * Copyright (c) 2008 IBM Corporation. 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: + * David Dykstal (IBM) - initial contribution. + *********************************************************************************/ + +package org.eclipse.rse.tests.persistence; + +import org.eclipse.rse.tests.core.RSECoreTestCase; + +/** + * + */ +public class MigrationTest extends RSECoreTestCase { + + public MigrationTest(String name) { + super(name); + } + + public void testProfileMigration() { + //-test-author-:DavidDykstal + // create a new profile + // set its persistence manager to PM1 + // populate the profile + // migrate profile to PM2 + // test for migration + // ensure that the old profile has been locked + } + +} diff --git a/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/persistence/PersistenceTestSuite.java b/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/persistence/PersistenceTestSuite.java index f2de8aa7553..d1a4054bc91 100644 --- a/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/persistence/PersistenceTestSuite.java +++ b/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/persistence/PersistenceTestSuite.java @@ -7,6 +7,7 @@ * * Contributors: * David Dykstal (IBM) - initial API and implementation + * David Dykstal (IBM) - [189274] provide import and export operations for profiles *******************************************************************************/ package org.eclipse.rse.tests.persistence; @@ -43,6 +44,10 @@ public class PersistenceTestSuite extends DelegatingTestSuiteHolder { suite.addTest(new PersistenceTest("testPersistenceManagerStartup")); suite.addTest(new PersistenceTest("testProfilePersistence")); suite.addTest(new PersistenceTest("testHostPersistence")); + suite.addTest(new ExportImportTest("testHost1")); + suite.addTest(new ExportImportTest("testFilterPool1")); + suite.addTest(new ExportImportTest("testPropertySet")); + suite.addTest(new MigrationTest("testProfileMigration")); return suite; }