Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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.
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -89,8 +86,6 @@ 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$
Expand Down Expand Up @@ -223,12 +218,13 @@ public void setInitializationData(IConfigurationElement config,
}

/**
* Return <code>null</code> if a valid workspace path has been set and an exit code otherwise.
* Prompt for and set the path if possible and required.
* Returns <code>null</code> 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 <code>null</code> if a valid instance location has been set and an exit code
* otherwise
* @return <code>null</code> if a valid instance location has been set and an
* exit code otherwise
*/
@SuppressWarnings("rawtypes")
protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
Expand Down Expand Up @@ -273,18 +269,11 @@ 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 = Workbench.getWorkspaceLockDetails(instanceLoc.getURL());
if (lockInfo != null) {
Workbench.showWorkspaceLockedDialog(workspaceDirectory.getAbsolutePath(), lockInfo);
}
MessageDialog.openError(
shell,
IDEWorkbenchMessages.IDEApplication_workspaceCannotLockTitle,
wsLockedError);
} else {
MessageDialog.openError(
shell,
Expand Down Expand Up @@ -378,7 +367,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 = Workbench.getWorkspaceLockDetails(workspaceUrl);

MessageDialog dialog = new MessageDialog(null, IDEWorkbenchMessages.IDEApplication_workspaceInUseTitle,
null, NLS.bind(IDEWorkbenchMessages.IDEApplication_workspaceInUseMessage, workspaceUrl.getFile()),
Expand Down Expand Up @@ -412,49 +401,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.
Expand Down Expand Up @@ -532,28 +478,14 @@ 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.
*
* @param workspaceUrl
* @return .lock_info file.
*/
private static Path createLockInfoFile(URL workspaceUrl) throws Exception {
Path lockInfoFile = getLockInfoFile(workspaceUrl);
Path lockInfoFile = Workbench.getLockInfoFile(workspaceUrl);
if (!Files.exists(lockInfoFile)) {
Files.createFile(lockInfoFile);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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. \
Expand Down Expand Up @@ -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}
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,12 @@
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.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
Expand All @@ -49,6 +52,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
Expand Down Expand Up @@ -80,6 +84,7 @@
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.preferences.ConfigurationScope;
Expand Down Expand Up @@ -114,6 +119,7 @@
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.e4.ui.workbench.modeling.ISaveHandler;
import org.eclipse.e4.ui.workbench.swt.internal.copy.WorkbenchSWTMessages;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
Expand Down Expand Up @@ -2699,7 +2705,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
* <code>null</code>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the returning constants is self explanatory, what does "return null" mean for the caller? NO exit? Don't care? Leave me alone with my problems?
Just imagine you would see this javadoc and not see the implementation. What you would think about this API?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add few more details then

*/
@SuppressWarnings("restriction")
public static Object setRestartArguments(String workspacePath) {
Expand All @@ -2714,6 +2721,16 @@ public static Object setRestartArguments(String workspacePath) {
if (command_line == null) {
return IApplication.EXIT_OK;
}
Path selectedWorkspace = Path.of(workspacePath);
try {
String workspaceLock = getWorkspaceLockDetails(selectedWorkspace.toUri().toURL());
if (workspaceLock != null && !workspaceLock.isEmpty()) {
showWorkspaceLockedDialog(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);
Expand Down Expand Up @@ -3684,4 +3701,72 @@ public void runWithInitialAutoScaleValue(Runnable runnable) {
}

}

/**
* Extract the lock details of the selected workspace if it is locked by another
* Eclipse application
*
* @param workspaceUrl the <code>URL</code> of selected workspace
* @return <code>String</code> details of lock owned workspace,
* <code>null or Empty</code> 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"); //$NON-NLS-1$
if (prop != null) {
lockDetails.append(NLS.bind(WorkbenchSWTMessages.IDEApplication_workspaceLockOwner, prop));
}
prop = properties.getProperty("host"); //$NON-NLS-1$
if (prop != null) {
lockDetails.append(NLS.bind(WorkbenchSWTMessages.IDEApplication_workspaceLockHost, prop));
}
prop = properties.getProperty("display"); //$NON-NLS-1$
if (prop != null) {
lockDetails.append(NLS.bind(WorkbenchSWTMessages.IDEApplication_workspaceLockDisplay, prop));
}
prop = properties.getProperty("process-id"); //$NON-NLS-1$
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 <code>URL</code> of selected workspace
* @return the path to the <code>.lock_info</code> file within the specified
* workspace, or <code> null</code> 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;
}
}

@SuppressWarnings("restriction")
public static void showWorkspaceLockedDialog(String workspacePath, String workspaceLock) {
String lockMessage = NLS.bind(WorkbenchSWTMessages.IDEApplication_workspaceCannotLockMessage2, workspacePath);
String wsLockedError = lockMessage + System.lineSeparator() + System.lineSeparator()
+ NLS.bind(WorkbenchSWTMessages.IDEApplication_workspaceLockMessage, workspaceLock);

MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've already commented before, if the workspace selection dialog is opened, there is NO active workbench window, not a single window is opened!

I would recommend to move all this workspace locking code to extra class and add a bold statement on the class javadoc that it is used in both workbench / window - free and workbench - created use cases.

WorkbenchSWTMessages.IDEApplication_workspaceCannotLockTitle, wsLockedError);
}
}
Loading