Installationsassistent / Ersteinrichtung

kaoZ

Top Contributor
Aloha , ich arbeite grade an einer Art Installations-Assitent , der es ermöglicht eine Grundeinrichtung meiner eigentlichen Applikation durchzuführen, nun zu folgender Frage:

Wie macht man sowas am besten / für gewöhnlich ?

Mein Ansatz ist wie folgt :

Beim starten meiner Eigentlichen Applikation sieht der Konstruktor so aus :

Java:
	public Editor() {
		if (checkState() != 1) {
			new Setup().showSetup();
		}
		else{
			setUpFrame();
			setUpComponents();
			setProperties();
			addComponents();
			setVisible();
		}
	}

und die dazugehörigen Methode checkState(); welche sich um das lesen eines Wertes aus einer im Build-Path befindlichen Properties Datei kümmert :

Java:
	private int checkState(){
		properties = PropertiesUtil.readProperties(DEFAULT_PROP_PATH);
		
		return Integer.parseInt(properties.getProperty("state"));
	}

Die selbst erstellte Utilityklasse ProperitesUtil kümmert sich in diesem Fall nur um das erstellen der in/outputStreams und das lesen einer vorab definierten "default_properties" Datei, in welcher ich nur 2 Werte halte:

Code:
#Default Properties
#Fri May 02 21:07:44 CEST 2014
root=null
state=0

Das Setup selbst hält eine Referenz auf ein SetupModel welches sich um das lesen und Schreiben der Daten kümmert,

Java:
public class SetupModel {
	
	private User user;
	private int state;
	private File rootDir;
	private Company company;
	private Properties properties;
	
	public SetupModel() {
		properties = new Properties();
	}
	
	public void setApplicationRoot(File dir){
		this.rootDir = dir;
	}
	
	public void setUser(User user){
		this.user = user;
	}
	
	public void setSetupState(int state){
		this.state = state;
	}
	
	public void setCompany(Company company){
		this.company = company;
	}
	
	public void storeData(){
		properties.setProperty("root", String.valueOf(getApplicationRoot()));
		properties.setProperty("state", String.valueOf(getSetupState()));
		
		/*Hier sollen später auch die Objekte 'user' + 'company' serialisiert
		 *in den rootpfad geschrieben werden ! 
		 *welche beim Applikationsstart dann ausgelesen werden sollen.
		 */
		PropertiesUtil.writeProperties(properties, DEFAULT_PROP_PATH, "Default Properties");
	}

	public User getUser() 				{return this.user;}
	public File getApplicationRoot() 	{return this.rootDir;}
	public Properties getProperties()	{return this.properties;}
	public Company getCompany() 		{return this.company;}
	public int getSetupState() 			{return this.state;}
}



genau da liegt jetzt meine Frage, ich erfasse über TextFelder die Daten , erstelle dann daraus Objekte und übergebe diese beim beenden des Setups über die Setter an das SetupModel welches dann über die
Code:
storeData();
Methode die Werte in der Properties Datei ändern soll, die Serialisierten Objekte in den 'Rootpfad' der Applikation Schreibt, dementsprechende Ordner für die Applikation erstellt und die Eigentliche Applikation startet.

macht man das so ? oder mache ich mir das jetzt einfach nur unfassbar umständlich ?

Auch beim Ansatz mit Model für die Daten und der Eigentlichen Sicht darauf ( Setup ) bin ich mir noch unschlüssig, ich habe mich hierbei an JTable und Co orientiert, welche ja auch die Referenz auf ein model zur Datenspeicherung haben. ( wobei es denke ich wesentliche übersichtlicher ist als alles in die eigentliche Darstellung zu stopfen ) nutzt man dann hier zusätzlich noch einen Extra Controller ? :rtfm:

Da ich ja vor Erstmaligem Programmstart eine Datei benötige die enthält ob schonmal ein Setup ausgeführt worden ist dachte ich ich nutze eben den Weg über die im Built-Path befindliche Properties Datei.

ich kann ja aus properties Dateien lediglich Strings als Wert erhalten , demnach müsste ich wenn ich z.B anstatt die Userdaten zu Serialisieren diese aus der Propertie Datei laden wollte, alle informationen einzeln speichern , da fand ich den Ansatz über das Serialisierte Objekt angenehmer,

würde mich freuen wenn mir jemand mit Erfahrung in diesem Bereich ein paar Tipps geben könnte , wie man sowas für gewöhnlich handhabt :)
 

kaoZ

Top Contributor
Naja ich wollte dies halt schon gern selbst realisieren , alleine schon zwecks des Lerneffektes, mir ging es vorwiegend darum wie man solch ein Assistenten sinnvoll gestalten kann um ihn dann auch unabhängig der eigentlichen Applikation nutzen zu können , so wie ich es mir dachte hält ja die Eigentliche Applikation lediglich eine Referenz auf eine im Built-Path befindliche Properties Datei, die halt standardmäßig nur den Rootpfad enthält welcher während des Assistenten erfasst wird, und ein Wert der stellvertretend dafür steht ob das Setup bereits ausgeführt wurde oder nicht.

Selber machen ist hier also meine Devise ;)
 

kaoZ

Top Contributor
Falls schonmal jemand solch einen Installations-Assistenten geschrieben hat wäre es super wenn er mir mal fix erläutert wie er an diese sache heran gegangen ist und welche möglichkeiten genutzt wurden ;)

Properties?Serialisierung? System Propertys?

Danke im vorraus .
 

turtle

Top Contributor
Ich vermute, das ich es nicht richtig verstanden habe...:oops:

Ich glaube verstanden zu haben, das du in einer default.properties Voreinstellungen hast, die möglicherweise später geändert werden. Also startet dein Programm mit einem Standard. Bei weiteren Starts sollen die (möglicherweise) geänderten Einstellungen genutzt werden. Ist das so richtig?

Wenn dem so ist, bin ich der Meinung das du überhaupt keinen Installer brauchst.

Das würde ich mit Java-Standard-Mitteln lösen und java.util.prefs.Preferences verwenden. Beim ersten Start findet das Programm keine Einträge und nimmt die Default-Values. Wird nun ein Parameter geändert, wird dieser neue Parameter gesetzt und in den Preferences gespeichert. Beim nächsten Start findet die Applikation den geänderten Parameter.

import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

public class Prefs {

public static void main(String[] args) {
try {
Preferences prefs = Preferences.userNodeForPackage(Prefs.class);
String parameter = prefs.get("SomeParameter", "DefaultValue");
System.out.println(parameter);
if (args.length == 1) {
prefs.put("SomeParameter", args[0]);
prefs.flush();
}
} catch (BackingStoreException e) {
e.printStackTrace();
}
}
}
Ansonsten habe ich mal izPack verwendet, bei dem man die üblichen Panels, die man so gewohnt ist bei Setup, als auch eigene Panels anlegen und in das Setup einbauen kann.
 

kaoZ

Top Contributor
Ich glaube verstanden zu haben, das du in einer default.properties Voreinstellungen hast, die möglicherweise später geändert werden. Also startet dein Programm mit einem Standard. Bei weiteren Starts sollen die (möglicherweise) geänderten Einstellungen genutzt werden. Ist das so richtig?

Quasi,

Das Programm an welchem ich zur zeit arbeite, bietet die Möglichkeit Kunden zu verwalten und für diese Kunden eben Rechnungen/Kostenvoranschläge zu erstellen.

Ebenso ist es möglich diese Rechnungen und Kostenvoranschläge nach ihrer erstellung zu speichern und zu drucken.

Nun möchte ich das wenn die Applikation das erste mal ausgeführt wird anhand einer Abfrage ( im jetzigen Fall dem auslesen eines Wertes aus einer Properties Datei ) ermittelt wird ob Das Programm schonmal ausgeführt wurde und erforderliche Daten wie Rootpfad ( "Installationspfad" ) zum hinterlegen der Daten, Benutzerdaten sowie Daten über die Nutzende Firma ( Welche während der "Ersteinrichtung" eben über diesen "Installations-Assistenten" erfasst werden , hinterlegt sind.

und fals dem so sein sollte, die Anwendung eben normal startet, und wenn nicht mein eigens erstellten "Installations-Assistent" öffnet.

In erster Linie ging es mir darum eben die Möglichkeit zu anzubieten , selber festzulegen wo die Daten abgelegt werden und vorher zu erfassen, welche Daten der Applikation zur Verfügung stehen , z.B um dann in den Rechnungen den Absender bereits festzulegen,

und darum dies, auch zu Lernzwecken, eben selbst zu realisieren, da ich so etwas vorher noch nicht gemacht habe dachte ich jemand hätte damit bereits Erfahrung wie man so etwas standardmäßig macht. :)

[EDIT]Danke für den Tipp mit den Preferences, hatte ich vollkommen vergessen und werde ich mir mal ansehen.[/EDIT]
 
Zuletzt bearbeitet:

TheSorm

Bekanntes Mitglied
naja ich denke Grundsätzlich ist das einfachste ein Programm mit einem JFileChoser zu schreiben in dem der Benutzter dann auswählen kann wo dein Programm instaliert werden soll und ob eine Desktop Verknüpfung eingestellt werden soll. Dann packt das java Programm die Jar vom richigen Programm in das gewählte verzeichniss wo auch die Toot datei angelegt wirt. In dieser datei wirt dann auch das verzeichniss eingetragen. dann kann das prgramm auslesen das in diesem Pfad gelesen und geschreiben werden soll.
 

kaoZ

Top Contributor
Also nochmal zusammenfassend vorab ,

Mein "Installations-Assistent" besteht aus einem Frame mit mehreren Paneln welches nacheinander benötigte Daten vom User abfragen,

selbstverständlich auch den Installationspfad über einen JFileChooser, unter anderem wird auf diesem Weg auch gleich eine Art Benutzer, und die Firma abgefragt, diese werden dann für den späteren bedarf als Serialisierte Daten in das während der Installation gewählte Root Verzeichniss geschrieben.

Quasi eine Ersteinrichtung der Applikation.

Wie ich das ganze nun letzendlich realisiere steht noch nicht ganz fest, ich werde mir dazu nochmal die Preferences API ansehen , und ansonsten den weg über Properties nutzen , funktioniert ja auch , schien mir nur irgendwie umständlich .
 

kaoZ

Top Contributor
@turtle

mal angenommen ich hätte nun folgende situation, wie würde man dies mit Preferences realisieren, ich hab schonmal etwas rumprobiert allerdings bin ich nicht wirklich zu einer Lösung gekommen

Beim start der Eigentlichen Applikation soll Controller anhand eines aus den Preferences ausgelesenen wertes entweder den Installer starten oder die Applikation selbst.

Java:
public class ApplicationController {

	Editor gui;
	Installer installer;
	
	public ApplicationController() {
		
		int i = 0; // hier würde ich dann den Wert aus den Preferences auslesen wollen.
		
		if (i != 0) {
			startGui();
		}
		else{
			startInstaller();
		}
		
	}
	
	private void startGui(){
		gui = new Editor();
		gui.setVisible();
	}
	
	private void startInstaller(){
		installer = new Installer();
		installer.setVisible();
	}
	
	public static void main(String[] args) {
		new ApplicationController();
	}
	
}

oder müsste ich dann am ende des Installers z.B mit .putBoolean("String", b);
den Wert setzen um ihn dann beim starten des Controllers auszulesen ?

also quasi

im Installer dann beim aufruf der storeData Methode:
Java:
public void storeData(){
		
		Preferences prefs = Preferences.userNodeForPackage(InstallerModel.class);
		
		prefs.putBoolean("state", true); // ? 
		
		File clientDir = new File(getApplicationRoot().toString() + "/Kundendaten");
		clientDir.mkdir();
		
		SerializeUtil.serializeObject(user, getApplicationRoot().toString(), user.getName().getFirstName() + USER_FORMAT);
	//	SerializeUtil.serializeObject(company, getApplicationRoot().toString(), company.getName().toString() + COMPANY_FORMAT);
	}
 

turtle

Top Contributor
Java:
	public static void main(String[] args) {
		Preferences prefs = Preferences.userNodeForPackage(Prefs.class);
		String x = prefs.get("installDirectory", "");
		if (x.length() > 0) {
			// Applikation starten
			System.out.println("Installiert in " + x);
		} else {
			// Installer starten
			System.out.println("Noch nicht installiert");
			JFileChooser fc = new JFileChooser();
			fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
			int returnVal = fc.showOpenDialog(null);
			if (returnVal == JFileChooser.APPROVE_OPTION) {
				File file = fc.getSelectedFile();
				prefs.put("installDirectory", file.getAbsolutePath());
			}
		}
	}
 

kaoZ

Top Contributor
So scheint es zu funktionieren :

Java:
public class ApplicationController {

	Editor gui;
	Installer installer;
	
	static Preferences prefs = Preferences.userNodeForPackage(Editor.class); 
	
	public ApplicationController() {
		
		int state = prefs.getInt("setupState", -1); // <-- der Default Wert
		
		if (state == 1) {
			startGui();
		}
		else if(state == -1){
			startInstaller();
		}
		
	}
	
	private void startGui(){
		gui = new Editor();
		gui.setVisible();
	}
	
	private void startInstaller(){
		installer = new Installer();
		installer.setVisible();
	}
	
	public static void main(String[] args) {
		new ApplicationController();
	}
	
}

und hier nochmal die storeData Methode des InstallerModels:

Java:
public void storeData(){
		
		Preferences prefs = Preferences.userNodeForPackage(Editor.class);
		
		prefs.putInt("setupState", 1);  // <<--
		
		File clientDir = new File(getApplicationRoot().toString() + "/Kundendaten");
		clientDir.mkdir();
		
		//SerializeUtil.serializeObject(user, getApplicationRoot().toString(), user.getName().getFirstName() + USER_FORMAT);
	//	SerializeUtil.serializeObject(company, getApplicationRoot().toString(), company.getName().toString() + COMPANY_FORMAT);
	}

wenn ich userNodeForPackage(class); verwende, dachte ich eigentlich das ich die Klasse angeben muss der ich Zugang zur Preferences gewähren möchte,

zum Verständnis , ich erstellte in meinem Fall einen neuen Koten FÜR die Klasse welche ich angebe, wenn ich jetzt wie oben

Code:
prefs = userNodeForPackage(Editor.class);
angebe, erstelle ich also einen neuen Knoten für diese Klasse ,

nun würde mich Interessieren , wo werden diese Werte Hinterlegt ? In der Windows Registry ja nur wenn ich SystemNodeForPackage(); aufrufe oder nicht ?

so ganz check ich das noch nicht, ich starte meine Applikation ja später einfach über eine Ausführbare .jar, wo genau werden diese Werte denn dann hinterlegt ? oder muss ich das Preferences Objekt dann irgendwo Persistent speichern und wieder einlesen ?

[EDIT]
The data is stored persistently in an implementation-dependent backing store.
[/EDIT]

ah, ok ;)

also wenn ich nun für meine Eigentliche Applikation Voreinstellungen zur Verfügung stellen möchte wie z.B den Rootpfad, kann ich diese Informationen einfach an das Preferences Objekt z.B

über die jeweiligen put Methoden übergeben , und muss mich nicht um die Persistente Speicherung kümmern.?!

Und kann so auch für jede Klasse eigene Einstellungen vornehmen indem ich einfach die Jeweilige klasse an das Preferences Objekt übergebe ?

Danke nochmal im vorraus .

So entnimmt mein ApplicationController im obrigen Fall also Informationen aus einem Preferences Objekt, welches ich im Installer FÜR meine Applikation ( Editor ) erstellt und mit Informationen versehen habe , ist das soweit korrekt ? :)
 
Zuletzt bearbeitet:

kaoZ

Top Contributor
Alles klar, ich hab mich in die API eingelesen und muss sagen das es einfacher ist als gedacht :)

SystemNodeForPackage(); erstellt also im SystemTree ein Schlüssel-Wert Paar

und

UserNodeForPackage(); einen Schlüssel-Wert Paar im Current-User Tree ,

danke nochmal für den Tipp mit den Preferences , klappt wunderbar ;)
 

Oben