diff --git a/bundles/org.eclipse.e4.ui.workbench.swt/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.ui.workbench.swt/META-INF/MANIFEST.MF index 8ecfefafc54..653acf36f81 100644 --- a/bundles/org.eclipse.e4.ui.workbench.swt/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.e4.ui.workbench.swt/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.e4.ui.workbench.swt;singleton:=true -Bundle-Version: 0.17.1000.qualifier +Bundle-Version: 0.17.1100.qualifier Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/workbench/swt/internal/copy/WorkbenchSWTMessages.java b/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/workbench/swt/internal/copy/WorkbenchSWTMessages.java index d7edc32bd8d..addfe96e481 100644 --- a/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/workbench/swt/internal/copy/WorkbenchSWTMessages.java +++ b/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/workbench/swt/internal/copy/WorkbenchSWTMessages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2019 IBM Corporation and others. + * Copyright (c) 2005, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -42,6 +42,17 @@ public class WorkbenchSWTMessages extends NLS { public static String InternalError; public static String IDEApplication_versionTitle; public static String IDEApplication_versionMessage; + public static String IDEApplication_workspaceLockMessage; + + public static String IDEApplication_workspaceLockOwner; + + public static String IDEApplication_workspaceLockHost; + + public static String IDEApplication_workspaceLockDisplay; + + public static String IDEApplication_workspaceLockPID; + + public static String IDEApplication_workspaceCannotLockMessage2; static { // load message values from bundle file diff --git a/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/workbench/swt/internal/copy/messages.properties b/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/workbench/swt/internal/copy/messages.properties index 4bfe270a62e..b27474e8284 100644 --- a/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/workbench/swt/internal/copy/messages.properties +++ b/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/workbench/swt/internal/copy/messages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2000, 2019 IBM Corporation and others. +# Copyright (c) 2000, 2025 IBM Corporation and others. # # This program and the accompanying materials # are made available under the terms of the Eclipse Public License 2.0 @@ -42,3 +42,9 @@ This workspace was written with a different version of the product and needs to {0}\n\n\ Updating the workspace may make it incompatible with other versions of the product.\n\ Press OK to update the workspace and open it. Press Cancel to select a different workspace. +IDEApplication_workspaceLockOwner=User:\t\t{0}\n +IDEApplication_workspaceLockHost=Host:\t\t{0}\n +IDEApplication_workspaceLockDisplay=Display:\t\t{0}\n +IDEApplication_workspaceLockPID=Process ID:\t{0}\n +IDEApplication_workspaceLockMessage=Workspace lock is currently held by:\n{0} +IDEApplication_workspaceCannotLockMessage2=Could not switch to the selected workspace ''{0}'' because it is currently in use by another Eclipse instance. \ No newline at end of file diff --git a/bundles/org.eclipse.ui.ide.application/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.ide.application/META-INF/MANIFEST.MF index 8e8ed96585b..52a3fe6de86 100644 --- a/bundles/org.eclipse.ui.ide.application/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.ui.ide.application/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Plugin.name Bundle-SymbolicName: org.eclipse.ui.ide.application;singleton:=true -Bundle-Version: 1.5.900.qualifier +Bundle-Version: 1.5.1000.qualifier Bundle-Vendor: %Plugin.providerName Bundle-Localization: plugin Require-Bundle: org.eclipse.ui.ide;bundle-version="[3.21.0,4.0.0)", diff --git a/bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java b/bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java index de109fddcea..f01771fd248 100644 --- a/bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java +++ b/bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2003, 2020 IBM Corporation and others. + * Copyright (c) 2003, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -24,11 +24,9 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.MalformedURLException; -import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; @@ -42,7 +40,6 @@ import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.URIUtil; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.preferences.ConfigurationScope; import org.eclipse.equinox.app.IApplication; @@ -65,6 +62,7 @@ import org.eclipse.ui.PlatformUI; import org.eclipse.ui.internal.Workbench; import org.eclipse.ui.internal.WorkbenchPlugin; +import org.eclipse.ui.internal.WorkspaceLock; import org.eclipse.ui.internal.ide.ChooseWorkspaceData; import org.eclipse.ui.internal.ide.ChooseWorkspaceDialog; import org.eclipse.ui.internal.ide.IDEInternalPreferences; @@ -89,19 +87,10 @@ public class IDEApplication implements IApplication, IExecutableExtension { private static final String VERSION_FILENAME = "version.ini"; //$NON-NLS-1$ - private static final Path LOCK_INFO_FILE = Path.of(METADATA_FOLDER, ".lock_info"); //$NON-NLS-1$ - private static final String DISPLAY_VAR = "DISPLAY"; //$NON-NLS-1$ private static final String HOST_NAME_VAR = "HOSTNAME"; //$NON-NLS-1$ - private static final String PROCESS_ID = "process-id"; //$NON-NLS-1$ - - private static final String DISPLAY = "display"; //$NON-NLS-1$ - - private static final String HOST = "host"; //$NON-NLS-1$ - - private static final String USER = "user"; //$NON-NLS-1$ private static final String USER_NAME = "user.name"; //$NON-NLS-1$ @@ -223,12 +212,13 @@ public void setInitializationData(IConfigurationElement config, } /** - * Return null if a valid workspace path has been set and an exit code otherwise. - * Prompt for and set the path if possible and required. + * Returns null if a valid workspace has been selected or locked + * successfully, and an exit code otherwise. Prompts for and sets the workspace + * path if required. * * @param applicationArguments the command line arguments - * @return null if a valid instance location has been set and an exit code - * otherwise + * @return null if a valid instance location has been set and an + * exit code otherwise */ @SuppressWarnings("rawtypes") protected Object checkInstanceLocation(Shell shell, Map applicationArguments) { @@ -273,18 +263,12 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) { return EXIT_WORKSPACE_LOCKED; } - String wsLockedError = NLS.bind(IDEWorkbenchMessages.IDEApplication_workspaceCannotLockMessage, - workspaceDirectory.getAbsolutePath()); // check if there is a lock info then append it to error message. - String lockInfo = getWorkspaceLockInfo(instanceLoc.getURL()); - if (lockInfo != null && !lockInfo.isBlank()) { - wsLockedError = wsLockedError + System.lineSeparator() + System.lineSeparator() - + NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Message, lockInfo); + String lockInfo = WorkspaceLock.getWorkspaceLockDetails(instanceLoc.getURL()); + if (lockInfo != null) { + WorkspaceLock.showWorkspaceLockedDialog(shell, workspaceDirectory.getAbsolutePath(), + lockInfo); } - MessageDialog.openError( - shell, - IDEWorkbenchMessages.IDEApplication_workspaceCannotLockTitle, - wsLockedError); } else { MessageDialog.openError( shell, @@ -378,7 +362,7 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) { // by this point it has been determined that the workspace is // already in use -- force the user to choose again - String lockInfo = getWorkspaceLockInfo(workspaceUrl); + String lockInfo = WorkspaceLock.getWorkspaceLockDetails(workspaceUrl); MessageDialog dialog = new MessageDialog(null, IDEWorkbenchMessages.IDEApplication_workspaceInUseTitle, null, NLS.bind(IDEWorkbenchMessages.IDEApplication_workspaceInUseMessage, workspaceUrl.getFile()), @@ -412,49 +396,6 @@ protected Control createCustomArea(Composite parent) { } } - /** - * Read workspace lock file and parse all the properties present. Based on the - * eclipse version and operating system some or all the properties may not - * present. In such scenario it will return empty string. - * - * @return Previous lock owner details. - */ - protected String getWorkspaceLockInfo(URL workspaceUrl) { - try { - Path lockFile = getLockInfoFile(workspaceUrl); - if (!Files.exists(lockFile)) { - return null; - } - - StringBuilder sb = new StringBuilder(); - Properties props = new Properties(); - try (InputStream is = Files.newInputStream(lockFile)) { - props.load(is); - String prop = props.getProperty(USER); - if (prop != null) { - sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_User, prop)); - } - prop = props.getProperty(HOST); - if (prop != null) { - sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Host, prop)); - } - prop = props.getProperty(DISPLAY); - if (prop != null) { - sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Disp, prop)); - } - prop = props.getProperty(PROCESS_ID); - if (prop != null) { - sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_P_Id, prop)); - } - return sb.toString(); - } - } catch (Exception e) { - IDEWorkbenchPlugin.log("Could not read lock info file: ", e); //$NON-NLS-1$ - - } - return null; - } - /** * Write lock owner details onto workspace lock file. Data includes user, host, * display and current java process id. @@ -464,19 +405,19 @@ protected void writeWsLockInfo(URL workspaceUrl) { String user = System.getProperty(USER_NAME); if (user != null) { - props.setProperty(USER, user); + props.setProperty(WorkspaceLock.USER, user); } String host = getHostName(); if (host != null) { - props.setProperty(HOST, host); + props.setProperty(WorkspaceLock.HOST, host); } String display = getDisplay(); if (display != null) { - props.setProperty(DISPLAY, display); + props.setProperty(WorkspaceLock.DISPLAY, display); } String pid = getProcessId(); if (pid != null) { - props.setProperty(PROCESS_ID, pid); + props.setProperty(WorkspaceLock.PROCESS_ID, pid); } if (props.isEmpty()) { @@ -532,20 +473,6 @@ private String getHostName() { return hostName; } - /** - * Returns the .lock_info file. Does not check if it exists. - * - * @param workspaceUrl - * @return .lock_info file. - */ - private static Path getLockInfoFile(URL workspaceUrl) { - try { - return Path.of(URIUtil.toURI(workspaceUrl)).resolve(LOCK_INFO_FILE); - } catch (URISyntaxException e) { - throw new IllegalArgumentException(e); - } - } - /** * Creates the .lock_info file if it does not exist. * @@ -553,7 +480,7 @@ private static Path getLockInfoFile(URL workspaceUrl) { * @return .lock_info file. */ private static Path createLockInfoFile(URL workspaceUrl) throws Exception { - Path lockInfoFile = getLockInfoFile(workspaceUrl); + Path lockInfoFile = WorkspaceLock.getLockInfoFile(workspaceUrl); if (!Files.exists(lockInfoFile)) { Files.createFile(lockInfoFile); } @@ -929,4 +856,4 @@ public void stop() { } }); } -} +} \ No newline at end of file diff --git a/bundles/org.eclipse.ui.ide/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.ide/META-INF/MANIFEST.MF index c115a47b5f6..0d2916a41cb 100644 --- a/bundles/org.eclipse.ui.ide/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.ui.ide/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Plugin.name Bundle-SymbolicName: org.eclipse.ui.ide; singleton:=true -Bundle-Version: 3.22.800.qualifier +Bundle-Version: 3.22.900.qualifier Bundle-Activator: org.eclipse.ui.internal.ide.IDEWorkbenchPlugin Bundle-ActivationPolicy: lazy Bundle-Vendor: %Plugin.providerName diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java index 0a14c764d01..bec664b18a5 100644 --- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2017 IBM Corporation and others. + * Copyright (c) 2005, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -1050,8 +1050,6 @@ public class IDEWorkbenchMessages extends NLS { public static String IDEApplication_workspaceInvalidMessage; public static String IDEApplication_workspaceCannotBeSetTitle; public static String IDEApplication_workspaceCannotBeSetMessage; - public static String IDEApplication_workspaceCannotLockTitle; - public static String IDEApplication_workspaceCannotLockMessage; public static String IDEApplication_versionTitle_newerWorkspace; public static String IDEApplication_versionTitle_olderWorkspace; public static String IDEApplication_versionMessage_newerWorkspace; @@ -1147,13 +1145,7 @@ public class IDEWorkbenchMessages extends NLS { public static String WorkbenchPreference_maxSimultaneousBuilds; public static String WorkbenchPreference_maxSimultaneousBuildIntervalError; - - public static String IDEApplication_Ws_Lock_Owner_User; - public static String IDEApplication_Ws_Lock_Owner_Host; - public static String IDEApplication_Ws_Lock_Owner_Disp; - public static String IDEApplication_Ws_Lock_Owner_P_Id; public static String IDEApplication_Ws_Lock_Owner_Message; - static { // load message values from bundle file NLS.initializeMessages(BUNDLE_NAME, IDEWorkbenchMessages.class); diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties index b79612e23ef..348c34e50b9 100644 --- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2000, 2022 IBM Corporation and others. +# Copyright (c) 2000, 2025 IBM Corporation and others. # # This program and the accompanying materials # are made available under the terms of the Eclipse Public License 2.0 @@ -1074,8 +1074,6 @@ IDEApplication_workspaceInvalidTitle=Invalid Workspace IDEApplication_workspaceInvalidMessage=Selected workspace is not valid; choose a different one. IDEApplication_workspaceCannotBeSetTitle=Workspace Cannot Be Created IDEApplication_workspaceCannotBeSetMessage=Could not launch the product because the specified workspace cannot be created. The specified workspace directory is either invalid or read-only. -IDEApplication_workspaceCannotLockTitle=Workspace Cannot Be Locked -IDEApplication_workspaceCannotLockMessage=Could not launch the product because the associated workspace at ''{0}'' is currently in use by another Eclipse application. IDEApplication_versionTitle_olderWorkspace=Older Workspace Version IDEApplication_versionTitle_newerWorkspace=Newer Workspace Version IDEApplication_versionMessage_olderWorkspace=The ''{0}'' workspace was written with an older version. \ @@ -1152,8 +1150,4 @@ editorAssociationOverride_error_couldNotCreate_message=The ''{0}'' extension fro editorAssociationOverride_error_invalidElementName_message=An extension from plug-in ''{0}'' to the ''org.eclipse.ui.ide.editorAssociationOverride'' extension point was ignored because it contains the following invalid element: ''{1}''. editorAssociationOverride_error_invalidExtension_message=The ''{0}'' extension from plug-in ''{1}'' to the ''org.eclipse.ui.ide.editorAssociationOverride'' extension point will be ignored because it contains invalid attributes. -IDEApplication_Ws_Lock_Owner_User=User:\t\t{0}\n -IDEApplication_Ws_Lock_Owner_Host=Host:\t\t{0}\n -IDEApplication_Ws_Lock_Owner_Disp=Display:\t\t{0}\n -IDEApplication_Ws_Lock_Owner_P_Id=Process ID:\t{0}\n IDEApplication_Ws_Lock_Owner_Message=Workspace lock is currently held by:\n{0} diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java index 690aa8ac9de..4709a4c19cc 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java @@ -35,9 +35,11 @@ import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; +import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -2699,7 +2701,8 @@ private static String buildCommandLine(String workspace) { * as the workspace location. * * @param workspacePath the new workspace location - * @return {@link IApplication#EXIT_OK} or {@link IApplication#EXIT_RELAUNCH} + * @return {@link IApplication#EXIT_OK} or {@link IApplication#EXIT_RELAUNCH} or + * null if workspace is locked */ @SuppressWarnings("restriction") public static Object setRestartArguments(String workspacePath) { @@ -2714,6 +2717,16 @@ public static Object setRestartArguments(String workspacePath) { if (command_line == null) { return IApplication.EXIT_OK; } + Path selectedWorkspace = Path.of(workspacePath); + try { + String workspaceLock = WorkspaceLock.getWorkspaceLockDetails(selectedWorkspace.toUri().toURL()); + if (workspaceLock != null) { + WorkspaceLock.showWorkspaceLockedDialog(null, workspacePath, workspaceLock); + return null; + } + } catch (MalformedURLException e) { + return null; + } System.setProperty(Workbench.PROP_EXIT_CODE, IApplication.EXIT_RELAUNCH.toString()); System.setProperty(IApplicationContext.EXIT_DATA_PROPERTY, command_line); @@ -3684,4 +3697,4 @@ public void runWithInitialAutoScaleValue(Runnable runnable) { } } -} +} \ No newline at end of file diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkspaceLock.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkspaceLock.java new file mode 100644 index 00000000000..5c95d176eb0 --- /dev/null +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkspaceLock.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2025 IBM Corporation. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Properties; +import org.eclipse.core.runtime.URIUtil; +import org.eclipse.e4.ui.workbench.swt.internal.copy.WorkbenchSWTMessages; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.widgets.Shell; + +/** + * Utility class for reading and presenting workspace lock information. + * + *

+ * This class is used during two different phases of the Eclipse application + * lifecycle: + *

+ * + * + *

+ * To support both environments, this class does not rely on workbench-specific + * APIs such as {@code PlatformUI.getWorkbench()} or {@code IWorkbenchWindow}, + * nor on any API that requires an initialized workbench window. Only SWT-level + * constructs (for example, {@link org.eclipse.swt.widgets.Display} and + * {@link org.eclipse.swt.widgets.Shell}) and core/runtime APIs are used. + *

+ * + * @since 3.5 + */ +public class WorkspaceLock { + + public static final String PROCESS_ID = "process-id"; //$NON-NLS-1$ + + public static final String DISPLAY = "display"; //$NON-NLS-1$ + + public static final String HOST = "host"; //$NON-NLS-1$ + + public static final String USER = "user"; //$NON-NLS-1$ + + /** + * Extract the lock details of the selected workspace if it is locked by another + * Eclipse application + * + * @param workspaceUrl the URL of selected workspace + * @return String details of lock owned workspace, + * null or Empty if not locked + */ + @SuppressWarnings("restriction") + public static String getWorkspaceLockDetails(URL workspaceUrl) { + Path lockFile = getLockInfoFile(workspaceUrl); + if (lockFile != null && Files.exists(lockFile)) { + StringBuilder lockDetails = new StringBuilder(); + Properties properties = new Properties(); + try (InputStream is = Files.newInputStream(lockFile)) { + properties.load(is); + String prop = properties.getProperty(USER); + if (prop != null) { + lockDetails.append(NLS.bind(WorkbenchSWTMessages.IDEApplication_workspaceLockOwner, prop)); + } + prop = properties.getProperty(HOST); + if (prop != null) { + lockDetails.append(NLS.bind(WorkbenchSWTMessages.IDEApplication_workspaceLockHost, prop)); + } + prop = properties.getProperty(DISPLAY); + if (prop != null) { + lockDetails.append(NLS.bind(WorkbenchSWTMessages.IDEApplication_workspaceLockDisplay, prop)); + } + prop = properties.getProperty(PROCESS_ID); + if (prop != null) { + lockDetails.append(NLS.bind(WorkbenchSWTMessages.IDEApplication_workspaceLockPID, prop)); + } + + } catch (IOException e) { + WorkbenchPlugin.log(e); + } + return lockDetails.toString(); + } + return null; + } + + /** + * Returns the lock file. + * + * @param workspaceUrl the URL of selected workspace + * @return the path to the .lock_info file within the specified + * workspace, or null if the workspace URL cannot be + * converted to a valid URI + */ + public static Path getLockInfoFile(URL workspaceUrl) { + Path lockFile = Path.of(".metadata", ".lock_info"); //$NON-NLS-1$ //$NON-NLS-2$ + try { + return Path.of(URIUtil.toURI(workspaceUrl)).resolve(lockFile); + } catch (URISyntaxException e) { + return null; + } + } + + /** + * Opens an error dialog indicating that the selected workspace is locked by + * another Eclipse instance. + *

+ * This method works in both early startup (before the Workbench is created) and + * in normal runtime (after Workbench windows exist). + *

+ * + * @param shell the parent {@link Shell} for the dialog, or + * {@code null} if no workbench window is available + * @param workspacePath the absolute path of the workspace that could not + * be locked + * @param workspaceLockOwner a formatted description of the existing lock owner + */ + @SuppressWarnings("restriction") + public static void showWorkspaceLockedDialog(Shell shell, String workspacePath, String workspaceLockOwner) { + String lockMessage = NLS.bind(WorkbenchSWTMessages.IDEApplication_workspaceCannotLockMessage2, workspacePath); + String wsLockedError = lockMessage + System.lineSeparator() + System.lineSeparator() + + NLS.bind(WorkbenchSWTMessages.IDEApplication_workspaceLockMessage, workspaceLockOwner); + + MessageDialog.openError(shell, + WorkbenchSWTMessages.IDEApplication_workspaceCannotLockTitle, wsLockedError); + } + +}