# Workspace & Preference-Scopes (mal wieder)



## dzim (22. Jan 2010)

Hallo Zusammen,

ich habe folgendes kleines Problem:

Ich habe - ähnlich wie es in Eclipse getan wird - einen Dialog, der noch vorm Application-Start geöffnet wird, um mir einen Workspace auszuwählen.
Das funktioniert so weit so gut, aber heute fiel mir auf, das in meiner App, immer noch der "workspace"-Ordner in meinen Programm-Ordner erstellt wird, in dem alle DialogSetting, Preferences u.s.w. liegen.

Ich denke, ich müsste hier einen Switch zu der eigentlichen API machen: Sprich, den Workspace anhand meiner Auswahl setzen und evtl. auch mehr mit den preference scopes rum spielen.

Meine Fragen:
* wie kann ich den Workspace einstellen (im RessourcePlugin konnte ich ihn nur auslesen...)
* wo werden die Preferences gespeichert (Verzeichnis/Datei), wenn ich z.B. das hier mache

```
Preferences prefs = new InstanceScope()
				.getNode(SSDToolPlugin.PLUGIN_ID);
		prefs.put(SSDToolPreferenceConstants.SSDTOOL_RECENT_WORKSPACES_SHOW, ""
				+ showWSDialog);
```

Ich hoffe, ihr versteht was ich meine...

Vielen Dank schon mal,
Daniel

edit:

bisher mache ich es so:

```
SSDToolPlugin.getDefault().getPreferenceStore().setValue(
				SSDToolPreferenceConstants.SSDTOOL_RECENT_WORKSPACES_SHOW,
				showWSDialog);
```
Das schein Configuration scope zu sein...
Und wird in meinen installationsverzeichnis unter workspace/.metadata/.plugins/org.eclipse.core.runtime/.settings/com.mycompany.ssdtool.prefs gespeichert


----------



## Wildcard (24. Jan 2010)

Der -data Startup Parameter legt den Workspace fest. Da bir dir wohl die Platform schon läuft, schau am besten mal in den Code des Eclipse eigenen Dialogs um zu sehen was dort genau passiert.
Instance Scope ist genau das gleiche wie der Default Scope, die settings landen also ebenfalls in workspace/.metadata.
Es gibt per Default 3 Scopes:
-Project Scope -> Pro Project, in PROJECT/.settings
-Instance Scope -> Pro Workspace in .metadata
-Installation Scope -> Pro Eclipse Installation, wo genau hängt von den Dateisystemrechten ab. Entweder in ECLIPSE/.configuration, oder in user home


----------



## dzim (26. Jan 2010)

Interessant ist, das aus Eclipse heraus der -data Parameter immer gesetzt wird (der Ordner wird anscheinend im Reiter Main in der location festgelegt - mach Sinn)
Aber auch, wenn ich das Programm exportiere und mittels Platform.getInstanceLocation() mir den Workspace rausgeben lasse, ist er auf den Ordner des exportierten Programms mit dem Unterordner workspace gesetzt.
In org.eclipse.ui.ide in der IDEApplication wird der Workspace-Auswahl-Dialog gezeigt und - wenn man nicht mit -data bereits was übergeben hat - der gewaähle Ordner mittels der (deprecated-)Methode Location.setURL(URL) gesetzt.
Ich habe das in meiner Anwendung probiert, mit dem Ergebnis, dass ich eine Exception bekommen, die mir mitteilt, das ich einen bereits gesetzten Workspace nicht umsetzten kann (ohne Neustart). So weit so gut, das versteh ich ja noch - wird ja auch in der javadoc so beschrieben.
Was ich gerade nicht verstehe: Ich mache es im Prinzip genau so, wie es in Eclipse gemacht wird (ich habe die entsprechende Methode kopiert und angepasst) und trotzdem geht es nicht!
Das ist echt Mist...


----------



## Wildcard (26. Jan 2010)

Und du rufst das in deiner eigenen Application auf bevor ein Workspace festgelegt wurde?
Setz mal einen Breakpoint in die setLocation und schau nach wer das aufruft (remote debugging)


----------



## SegFault (27. Jan 2010)

Ich hab aktuell das selbe Problem, weiss aber auch nicht wie man es lösen könnte set von Location wird direkt nach dem Starten der Anwendung schonmal ausgeführt noch bevor irgendwelche Plugins zum Greifen kommen. Aber wie kann man es trotz allem löschen den Workspace zu ändern?

Ich hab mir mal die Action methode angeschaut die das ganze über einen Neustart regelt. Aber wirklich helfen tut das auch nichts. Denn ein Workbench ist noch nicht erstellt. Mein aktuelles Ziel ist es vor dem erstellen des workbenches mit .createAndRunWorkbench() den Pfad für die ganzen Plugindaten etc zu ändern. Scheinbar kommt mir in die Quere das ja die Plugins schon geladen sind und damit auf einen workspace arbeiten. Ich möchte einfach jeden nutzer meines Programmes einen eigenen workspace anbieten. Die nutzer haben alle ein login im programm. Daher auch einen eigenen nutzernamen. Ich möchte nun den Workspace auf diesen namen umbiegen. Aktuelle Idee ist den nutzernamen und passwort eingeben lassen. Schauen ob der Workspace richtig gelegt ist, wenn ja das ganze fortführen, wenn nein muss ich den Pfad mit -Data neu setzen und die Anwendung neustarten, ich halte das nur für ziemlich viel Aufwand für wenig nutzen.

Da fällt mir noch ein. Ich müsste ja dann Passwort und Login beim neustart auch wieder per VM Args übergeben, wie sicher wäre denn das? Wie lese ich das am günstigsten wieder aus es gibt ja nicht mehr sowas wie String[] args in der main. ich kann mir AFAIK mit System.getProperty die Commandline ranholen aber parsen muss ich die dann wohl von hand?


----------



## dzim (29. Jan 2010)

Ich hab das ganze gestern noch etwas verfolgt, aber mehr, als dass es anscheinend aus einem Service Bundle geholt wird, hab ich bisher noch nicht rausgefunden.
Ich probier mich dann mal am Remote Debugging - so was hab ich bisher nur vom Hörensagen gekannt ;-)


----------



## dzim (29. Jan 2010)

Konkret holt sich die Platform die instanceLocation aus der Klasse InternalPlatiform über den Filter für den ServiceTracker "Location.INSTANCE_FILTER"

Die Methode ist 
[JAVA=371]
	public Location getInstanceLocation() {
		assertInitialized();
		if (instanceLocation == null) {
			Filter filter = null;
			try {
				filter = context.createFilter(Location.INSTANCE_FILTER);
			} catch (InvalidSyntaxException e) {
				// ignore this.  It should never happen as we have tested the above format.
			}
			instanceLocation = new ServiceTracker(context, filter, null);
			instanceLocation.open();
		}
		return (Location) instanceLocation.getService();
	}
[/code]

Den zugehörigen Service habe ich aber noch nicht gefunden.


----------



## dzim (16. Mrz 2010)

Woah! Das ist ja unglaublich!

Lange hatte ich mich nicht mehr mit diesem Problem beschäftigt, aber gestern habe ich mich mal wieder ran gewagt.

@Wildcard: Verspätet, aber: Danke noch mal für den Tipp mit dem -data Parameter - ich habe den mir noch einmal zur Brust genommen und mir ist klar geworden, das -data @noDefault der Parameter meiner Wahl ist.

Was habe ich geändert?

1) -data @noDefault als Startparameter, damit nicht das Problem mit dem bereits gesetzten Workspace auftauchen kann und ich noch die Möglichkeit habe, diesen selbst zu setzen.

2) Ich habe alle Preferences, die für die Auswahl des Workspaces zuständig sein könnten, also bei einem Dialog, der noch vor dem Start der Workbench auftauchen soll, nicht wie bisher über Plugin.getDefault().getPreferenceStore() geholt, da diese nur Instance Scope haben. Stattdessen bin ich dort auf Installation Scope (ConfigurationScope - hier auch noch mal danke @Vogella - Eclipse Preferences - Tutorial ) ungeschwenkt, so dass diese Prefs wie bei Eclipse pro Installation gültig sind.

3) Habe den Startvorgang von Eclipse selbst - so gut es eben geht - kopiert und bei mir eingebaut. Das wichtige ist hier eigentlich folgendes (alles in der Application-Klasse):

```
public Object start(IApplicationContext context) throws Exception {

		Display display = PlatformUI.createDisplay();
		try {

			// look and see if there's a splash shell we can parent off of
			Shell shell = WorkbenchPlugin.getSplashShell(display);
			if (shell != null) {
				// should should set the icon and message for this shell to the
				// same as the chooser dialog - this will be the guy that in
				// the task bar and without these calls you'd have the icon
				// with no message.
				shell.setText(OpenSSDToolWorkpaceDialog.WINDOW_TITLE);
				shell.setImages(Dialog.getDefaultImages());
			}

			boolean check = checkInstanceLocation(shell);

			if (!check) {
				WorkbenchPlugin.unsetSplashShell(display);
				Platform.endSplash();
				return IApplication.EXIT_OK;
			}

			// print the location via my logger for testing
			// (in my OWN workspace - quite unnecesarry, I know)
			Location instanceLoc = Platform.getInstanceLocation();
			if (instanceLoc != null) {
				Logger.logInfo(instanceLoc.getURL().getFile());
			}

			/*
			 * OLD approach, without setting the Location
			 * 
			 * explicit dialog call - interactive splash handlers don't allow
			 * cancel operation, when you want to abort the loading of the app.
			 * decided not to make the whole
			 * eclipse-check-workspace-version-validity-check-thing
			 */
			// if (SSDToolUtils.isShowWorkspaceSelectionDialog()) {
			//
			// OpenSSDToolWorkpaceDialog dialog = new OpenSSDToolWorkpaceDialog(
			// display.getActiveShell());
			//
			// if (dialog.open() == TitleAreaDialog.CANCEL) {
			// return IApplication.EXIT_OK;
			// }
			// }

			int returnCode = PlatformUI.createAndRunWorkbench(display,
					new ApplicationWorkbenchAdvisor());
			if (returnCode == PlatformUI.RETURN_RESTART) {
				return IApplication.EXIT_RESTART;
			}

			return IApplication.EXIT_OK;

		} finally {

			if (display != null) {
				display.dispose();
			}
		}
	}

	/**
	 * <b>THIS IS A COPY OF THE IDEApplication SAME METHOD, CHANGED TO FIT MY
	 * NEEDS!</b><br>
	 * Return true if a valid workspace path has been set and false otherwise.
	 * Prompt for and set the path if possible and required. <br>
	 * I decided not to make the whole
	 * eclipse-check-workspace-version-validity-check-thing
	 * 
	 * @author dzimmermann
	 * @return true if a valid instance location has been set and false
	 *         otherwise
	 */
	private boolean checkInstanceLocation(Shell shell) {

		Location instanceLoc = Platform.getInstanceLocation();

		// -data @none was specified but an ide requires workspace
		if (instanceLoc == null) {
			printErrorMessage(shell, SSDTOOL_APPLICATION_ERROR_MANDATORY_WS);
			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).
			if (!checkPathValidity(instanceLoc.getURL())) {
				return false;
			}

			// at this point its valid, so try to lock it and update the
			// metadata version information if successful
			try {
				if (instanceLoc.lock()) {
					// writeWorkspaceVersion();
					return true;
				}

				// 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()) {
					printErrorMessage(shell,
							SSDTOOL_APPLICATION_ERROR_CANNOT_LOCK_WS);
				} else {
					printErrorMessage(shell,
							SSDTOOL_APPLICATION_ERROR_CANNOT_SET_WS);
				}
			} catch (IOException e) {
				Logger.logError("Could not obtain lock for workspace location", //$NON-NLS-1$
						e);
				printErrorMessage(shell, e.getMessage());
			}
			return false;
		}

		// -data @noDefault or -data not specified, prompt and set

		boolean force = false;

		while (true) {

			OpenSSDToolWorkpaceDialog dialog = new OpenSSDToolWorkpaceDialog(
					shell);

			if (dialog.open() == TitleAreaDialog.CANCEL) {
				return false;
			}

			URL workspaceUrl = dialog.getCurrentWSAsURL();
			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, true)) {
					// writeWorkspaceVersion();
					return true;
				}
			} catch (IllegalStateException e) {
				Logger.logError(SSDTOOL_APPLICATION_ERROR_CANNOT_SET_WS, e);
				printErrorMessage(shell,
						SSDTOOL_APPLICATION_ERROR_CANNOT_SET_WS);
				return false;
			} catch (IOException e) {
				Logger.logError(SSDTOOL_APPLICATION_ERROR_CANNOT_SET_WS, e);
				printErrorMessage(shell,
						SSDTOOL_APPLICATION_ERROR_CANNOT_SET_WS);
				return false;
			}

			// by this point it has been determined that the workspace is
			// already in use -- force the user to choose again
			printErrorMessage(shell, SSDTOOL_APPLICATION_ERROR_WS_IN_USE);
		}
	}

	/**
	 * no metadata check here...
	 * 
	 * @param path
	 *            the url to check
	 * @return <code>true</code>, is the path is valid, else <code>false</code>
	 */
	private boolean checkPathValidity(URL path) {

		File f = new File(path.getFile());

		if (!f.isDirectory()) {
			return false;
		}

		return true;
	}

	/**
	 * default helper method to print an error
	 * 
	 * @param parentShell
	 *            the parent shell on where the message should pop up.
	 * @param message
	 *            the message to display
	 */
	private void printErrorMessage(Shell parentShell, String message) {

		MessageDialog.openError(parentShell,
				SSDTOOL_APPLICATION_ERROR_MESSAGE_TITLE, message);
	}
```

Jetzt geht es so weit.
Vielleicht gibt es bessere Annäherungen an das Problem, ich weiß es nicht, wenn ja: Bitte posten ;-)
Das selbe gilt für Verbesserungen...

Viele Grüße und viel Spaß damit, falls ihr es nicht schon selbst hinbekommen habt!

Daniel


----------

