Search code examples
javaeclipseworkspace

Error in creating new workspace in Eclipse RCP application


Problem in creating a new workspace in an Eclipse RCP application.

When the RCP application is launched, a dialog is prompted to ask the workspace location. When the location is given, then there is error saying "Could not launch the product because the specified workspace cannot be created. The specified workspace directory is either invalid or read-only". I have followed the code from IDEApplication.java from eclipse, but still I am facing same issue.

Application code:

@SuppressWarnings("restriction")
public class MyRcpApplication implements IApplication
{

  private static final String METADATA_PROJECTS_PATH = "/.plugins/org.eclipse.core.resources/.projects";
  private static final String METADATA_ROOT = ".metadata";
  private static final String COMMAND_ARG = "--container";
  private static final String SYSTEM_PROPERTY_EXIT_CODE = "eclipse.exitcode";
  private static final String WORKSPACE_VERSION_KEY = "org.eclipse.core.runtime";
  private static final String VERSION_FILENAME = "version.ini";
  private static final String WORKSPACE_VERSION_VALUE = "1"; //$NON-NLS-1$

  public static final String METADATA_FOLDER = ".metadata"; //$NON-NLS-1$
  private Shell shell;

  /*
   * (non-Javadoc)
   * 
   * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext)
   */
  @Override
  public Object start(final IApplicationContext context)
  {

    Display display = PlatformUI.createDisplay();
    Shell shell = display.getActiveShell();
    try
    {
      // for backward compatibility we need to clear the workspace before start also
      cleanUpTheWorkSpace();
      boolean instanceLocationCheck = checkInstanceLocation(shell, context.getArguments());
      if (!instanceLocationCheck)
      {
        MessageDialog.openError(shell, IDEWorkbenchMessages.IDEApplication_workspaceInUseTitle,
            "Could not launch the product because the associated workspace is currently in use by another My Application.");
        return IApplication.EXIT_OK;
      }

      int returnCode = PlatformUI.createAndRunWorkbench(display, new MyApplicationWorkbenchAdvisor());
      if (returnCode == PlatformUI.RETURN_RESTART)
      {
        // eclipse.exitcode system property may be set to re-launch
        if (IApplication.EXIT_RELAUNCH.equals(Integer.getInteger(SYSTEM_PROPERTY_EXIT_CODE)))
        {
          return IApplication.EXIT_RELAUNCH;
        }

        return IApplication.EXIT_RESTART;
      }
      // if application return code is exit clean up the workspace
      // cleanUpTheWorkSpace();
      return IApplication.EXIT_OK;
    }
    finally
    {
      if (display != null)
      {
        display.dispose();
      }
      Location instanceLoc = Platform.getInstanceLocation();
      if (instanceLoc != null)
      {
        instanceLoc.release();
      }
    }
  }

  @SuppressWarnings("rawtypes")
  private boolean checkInstanceLocation(final Shell shell, final Map arguments)
  {
    Location instanceLoc = Platform.getInstanceLocation();
    if (instanceLoc == null)
    {
      MessageDialog.openError(shell, "Workspace is Mandatory", "IDEs need a valid workspace.");
      return false;
    }

    // -data "/valid/path", workspace already set
    if (instanceLoc.isSet())
    {

      // make sure the meta data version is compatible (or the user has
      // chosen to overwrite it).
      try
      {
        // Used to check whether are we launching My application from development environment or not
        if (isDevLaunchMode(arguments))
        {
          return true;
        }
        // Used to check instance location is locked or not
        if (instanceLoc.isLocked())
        {
          return false;
        }
        // we failed to create the directory.
        // Two possibilities:
        // 1. directory is already in use
        // 2. directory could not be created
        File workspaceDirectory = new File(instanceLoc.getURL().getFile());
        if (workspaceDirectory.exists())
        {
          if (isDevLaunchMode(arguments))
          {
            return true;
          }
          MessageDialog.openError(
              shell,
              "Workspace Cannot Be Locked",
              "Could not launch the product because the associated workspace at '" + workspaceDirectory.getAbsolutePath()
                  + "' is currently in use by another Eclipse application");

        }
        else
        {
          MessageDialog
              .openError(
                  shell,
                  "Workspace Cannot Be Created",
                  "Could not launch the product because the specified workspace cannot be created.  The specified workspace directory is either invalid or read-only.");
        }
      }
      catch (IOException e)
      {
        MessageDialog.openError(shell, "Internal Error", e.getMessage());
      }
    }
    else
    {
      try
      {
        // -data @noDefault or -data not specified, prompt and set
        ChooseWorkspaceData launchData = new ChooseWorkspaceData(instanceLoc.getDefault());
        boolean force = false;
        while (true)
        {
          URL workspaceUrl = promptForWorkspace(shell, launchData, force);
          if (workspaceUrl == null)
          {
            return false;
          }

          // if there is an error with the first selection, then force the
          // dialog to open to give the user a chance to correct
          force = true;

          try
          {
            // the operation will fail if the url is not a valid
            // instance data area, so other checking is unneeded
            if (instanceLoc.set(workspaceUrl, false))
            {
              launchData.writePersistedData();
              writeWorkspaceVersion(workspaceUrl);
              return true;
            }
          }
          catch (IllegalStateException e)
          {
            MessageDialog
                .openError(
                    shell,
                    IDEWorkbenchMessages
                    .IDEApplication_workspaceCannotBeSetTitle,
                    IDEWorkbenchMessages
                    .IDEApplication_workspaceCannotBeSetMessage);
            return false;
          }

          // by this point it has been determined that the workspace is
          // already in use -- force the user to choose again
          MessageDialog.openError(shell, IDEWorkbenchMessages
              .IDEApplication_workspaceInUseTitle,
              IDEWorkbenchMessages.
              IDEApplication_workspaceInUseMessage);
        }
      }

      catch (IllegalStateException | IOException e)
      {
      }
    }

    return true;
  }

  private static void writeWorkspaceVersion(final URL defaultValue)
  {
    Location instanceLoc = Platform.getInstanceLocation();
    if (instanceLoc.isReadOnly())
    {
      // MessageDialog.openError(shell,"Read-Only Dialog", "Location was read-only");
      System.out.println("Instance Got Locked......");
    }
    if ((instanceLoc == null) || instanceLoc.isReadOnly())
    {
      return;
    }

    File versionFile = getVersionFile(instanceLoc.getURL(), true);
    if (versionFile == null)
    {
      return;
    }

    OutputStream output = null;
    try
    {
      String versionLine = WORKSPACE_VERSION_KEY + '=' + WORKSPACE_VERSION_VALUE;

      output = new FileOutputStream(versionFile);
      output.write(versionLine.getBytes("UTF-8")); //$NON-NLS-1$
    }
    catch (IOException e)
    {
      IDEWorkbenchPlugin.log("Could not write version file", //$NON-NLS-1$
          StatusUtil.newStatus(IStatus.ERROR, e.getMessage(), e));
    }
    finally
    {
      try
      {
        if (output != null)
        {
          output.close();
        }
      }
      catch (IOException e)
      {
        // do nothing
      }
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.eclipse.equinox.app.IApplication#stop()
   */
  @Override
  public void stop()
  {
    if (!PlatformUI.isWorkbenchRunning())
    {
      return;
    }
    final IWorkbench workbench = PlatformUI.getWorkbench();
    final Display display = workbench.getDisplay();
    display.syncExec(new Runnable()
    {
      @Override
      public void run()
      {
        if (!display.isDisposed())
        {
          workbench.close();
        }
      }
    });
  }

  private URL promptForWorkspace(final Shell shell, final ChooseWorkspaceData launchData, boolean force)
  {
    URL url = null;
    do
    {
      new ChooseWorkspaceDialog(shell, launchData, false, force).prompt(force);
      String instancePath = launchData.getSelection();
      if (instancePath == null)
      {
        return null;
      }

      // the dialog is not forced on the first iteration, but is on every
      // subsequent one -- if there was an error then the user needs to be
      // allowed to
      force = true;

      // create the workspace if it does not already exist
      File workspace = new File(instancePath);
      if (!workspace.exists())
      {
        workspace.mkdir();
      }

      try
      {
        // Don't use File.toURL() since it adds a leading slash that Platform does not
        // handle properly. See bug 54081 for more details.
        String path = workspace.getAbsolutePath().replace(File.separatorChar, '/');
        url = new URL("file", null, path); //$NON-NLS-1$
      }
      catch (MalformedURLException e)
      {
        MessageDialog
            .openError(
                shell,
                IDEWorkbenchMessages
                .IDEApplication_workspaceInvalidTitle,
                IDEWorkbenchMessages
                .IDEApplication_workspaceInvalidMessage);
        continue;
      }
    }
    while (!checkValidWorkspace(shell, url));

    return url;
  }

  private boolean checkValidWorkspace(final Shell shell, final URL url)
  {
    String version = readWorkspaceVersion(url);

    // if the version could not be read, then there is not any existing
    // workspace data to trample, e.g., perhaps its a new directory that
    // is just starting to be used as a workspace
    if (version == null)
    {
      return true;
    }

    final int ide_version = Integer.parseInt(WORKSPACE_VERSION_VALUE);
    int workspace_version = Integer.parseInt(version);

    // equality test is required since any version difference (newer
    // or older) may result in data being trampled
    if (workspace_version == ide_version)
    {
      return true;
    }

    // At this point workspace has been detected to be from a version
    // other than the current ide version -- find out if the user wants
    // to use it anyhow.
    String title = "My App Titile"; //$NON-NLS-1$
    String message = "My App Message";

    MessageBox mbox = new MessageBox(shell, SWT.OK | SWT.CANCEL
        | SWT.ICON_WARNING | SWT.APPLICATION_MODAL);
    mbox.setText(title);
    mbox.setMessage(message);
    return mbox.open() == SWT.OK;
  }

  private static String readWorkspaceVersion(final URL workspace)
  {
    File versionFile = getVersionFile(workspace, false);
    if ((versionFile == null) || !versionFile.exists())
    {
      return null;
    }

    try
    {
      // Although the version file is not spec'ed to be a Java properties
      // file, it happens to follow the same format currently, so using
      // Properties to read it is convenient.
      Properties props = new Properties();
      FileInputStream is = new FileInputStream(versionFile);
      try
      {
        props.load(is);
      }
      finally
      {
        is.close();
      }

      return props.getProperty(WORKSPACE_VERSION_KEY);
    }
    catch (IOException e)
    {
      IDEWorkbenchPlugin.log("Could not read version file", new Status( //$NON-NLS-1$
          IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH,
          IStatus.ERROR,
          e.getMessage() == null ? "" : e.getMessage(), //$NON-NLS-1$, 
          e));
      return null;
    }
  }

  private static File getVersionFile(final URL workspaceUrl, final boolean create)
  {
    if (workspaceUrl == null)
    {
      return null;
    }

    try
    {
      // make sure the directory exists
      File metaDir = new File(workspaceUrl.getPath(), METADATA_FOLDER);
      if (!metaDir.exists() && (!create || !metaDir.mkdir()))
      {
        return null;
      }

      // make sure the file exists
      File versionFile = new File(metaDir, VERSION_FILENAME);
      if (!versionFile.exists()
          && (!create || !versionFile.createNewFile()))
      {
        return null;
      }

      return versionFile;
    }
    catch (IOException e)
    {
      // cannot log because instance area has not been set
      return null;
    }
  }

  @SuppressWarnings("rawtypes")
  private static boolean isDevLaunchMode(final Map args)
  {
    // see org.eclipse.pde.internal.core.PluginPathFinder.isDevLaunchMode()
    if (Boolean.getBoolean("eclipse.pde.launch"))
    {
      return true;
    }
    return args.containsKey("-pdelaunch"); //$NON-NLS-1$
  }

  /**
   * Deletes all the available projects in the workspace
   */
  private void cleanUpTheWorkSpace()
  {
    // this will be the
    String[] commands = Platform.getCommandLineArgs();
    if (commands != null)
    {
      List<String> args = Arrays.asList(commands);
      if (args.contains(COMMAND_ARG))
      {
        // if project is in the root delete it.. it will delete associated metadata
        IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
        if (projects != null)
        {
          for (IProject project : projects)
          {
            try
            {
              project.delete(true, new NullProgressMonitor());
            }
            catch (CoreException e)
            {
              // msgHandler.post(MsgSeverity.ERROR, "Unable to clear the workspace");
            }
          }
        }
        // if project is not in the root but if its in the workspace delete the metadata too
        File[] workSpaceFiles = Platform.getLocation().toFile().listFiles();
        for (File file : workSpaceFiles)
        {
          if (METADATA_ROOT.equals(file.getName()))
          {
            File projectMeta = new File(file.getPath() + METADATA_PROJECTS_PATH);
            if ((projectMeta != null) && projectMeta.exists())
            {
              File[] children = projectMeta.listFiles();
              for (File child : children)
              {
                FileUtils.deleteQuietly(child);
              }
            }
          }

          /*
           * else { FileUtils.deleteQuietly(file); }
           */
        }
      }
    }
  }
}

Solution

  • Your code is just calling

    if (instanceLoc.isLocked())
     {
      return false;
     }
    

    to check if the workspace is locked, but is doing nothing to make the workspace locked so this will always fall through to the error code.

    IDEApplication does this:

    if (instanceLoc.lock()) {
      writeWorkspaceVersion();
      return null;
    }
    

    you need to do something similar.