1
|
|
/*
|
2
|
|
* JBind
|
3
|
|
*
|
4
|
|
* Copyright (c) by Stefan Wachter. All rights reserved.
|
5
|
|
*
|
6
|
|
* Usage, modification, and redistribution is subject to license terms that are
|
7
|
|
* available at 'http://www.jbind.org'. The JBind license is like the
|
8
|
|
* 'Apache Software License V 1.1'.
|
9
|
|
*/
|
10
|
|
package org.jbind.util.other;
|
11
|
|
|
12
|
|
import java.io.BufferedInputStream;
|
13
|
|
import java.io.BufferedOutputStream;
|
14
|
|
import java.io.File;
|
15
|
|
import java.io.FileInputStream;
|
16
|
|
import java.io.FileOutputStream;
|
17
|
|
import java.io.InputStream;
|
18
|
|
import java.io.OutputStream;
|
19
|
|
import java.util.prefs.Preferences;
|
20
|
|
|
21
|
|
import org.jbind.base.Console;
|
22
|
|
|
23
|
|
/**
|
24
|
|
* Base class for managing preferences. Derived classes can use the {@link
|
25
|
|
* #doMain} method to easily create a main method to manage the preferences.
|
26
|
|
*/
|
27
|
|
public abstract class Prefs {
|
28
|
|
|
29
|
|
private boolean mySystemNotUser;
|
30
|
|
private Preferences myPreferences = null;
|
31
|
|
|
32
|
|
/**
|
33
|
|
* Creates a prefs object that manages the preferences of class this instance
|
34
|
|
* belongs to.
|
35
|
|
*
|
36
|
|
* @param aSystemNotUser Determines if user or system preferences are to be
|
37
|
|
* managed.
|
38
|
|
*/
|
39
|
3
|
protected Prefs(boolean aSystemNotUser) {
|
40
|
3
|
mySystemNotUser = aSystemNotUser;
|
41
|
|
}
|
42
|
|
|
43
|
|
/**
|
44
|
|
* Gets the preferences of the class of this instance.
|
45
|
|
*
|
46
|
|
* @return <i>(required)</i>.
|
47
|
|
*/
|
48
|
2985
|
protected Preferences getPrefs() {
|
49
|
2985
|
if (null == myPreferences) {
|
50
|
6
|
if (mySystemNotUser) {
|
51
|
0
|
myPreferences = Preferences.systemNodeForPackage(getClass());
|
52
|
|
} else {
|
53
|
6
|
myPreferences = Preferences.userNodeForPackage(getClass());
|
54
|
|
}
|
55
|
|
}
|
56
|
2985
|
return myPreferences;
|
57
|
|
}
|
58
|
|
|
59
|
3
|
protected void resetPrefs() {
|
60
|
3
|
getPrefs();
|
61
|
3
|
try {
|
62
|
3
|
myPreferences.removeNode();
|
63
|
|
} catch (Exception e) {
|
64
|
0
|
e.printStackTrace();
|
65
|
|
}
|
66
|
3
|
myPreferences = null;
|
67
|
3
|
doResetPrefs();
|
68
|
|
}
|
69
|
|
|
70
|
|
/**
|
71
|
|
* Gets preferences addressed by an either relative or absolute path.
|
72
|
|
*
|
73
|
|
* @param aPath <i>(required)</i>.
|
74
|
|
* @return <i>(required)</i>.
|
75
|
|
*/
|
76
|
2982
|
protected Preferences getPrefs(String aPath) {
|
77
|
2982
|
return getPrefs().node(aPath);
|
78
|
|
}
|
79
|
|
|
80
|
|
/**
|
81
|
|
* Prints usage information for the {@link #doMain} method on {@link org.jbind.base.Console#err Console.err}.
|
82
|
|
*/
|
83
|
0
|
protected void usage() {
|
84
|
0
|
Console.err("usage:");
|
85
|
0
|
Console.err("\tjava " + getClass().getName() + " -export <fileName> -import <fileName> -remove -reset -path [<path>] -setKeyValue <key> <value> -removeKey <key>");
|
86
|
0
|
Console.err("\t\texport : exports the preferences to a file");
|
87
|
0
|
Console.err("\t\timport : imports preferences from a file. Any former preferences are replaced");
|
88
|
0
|
Console.err("\t\tremove : removes the preferences");
|
89
|
0
|
Console.err("\t\treset : resets the preferences");
|
90
|
0
|
Console.err("\t\tpath : sets the current path.");
|
91
|
0
|
Console.err("\t\tsetKeyValue: sets a key value pair (at the current path). The value can not contain a space.");
|
92
|
0
|
Console.err("\t\tremoveKey : removes a key value pair (at the current path).");
|
93
|
0
|
Console.err("The arguments are processed in the same sequence as they appear on the command line.");
|
94
|
|
}
|
95
|
|
|
96
|
|
/**
|
97
|
|
* Manages the preferences by applying the arguments supplied in an argument
|
98
|
|
* array. The argument array may contain the following options:
|
99
|
|
* <ul>
|
100
|
|
* <li>-export <fileName></li>
|
101
|
|
* <li>-import <fileName</li>
|
102
|
|
* <li>-remove</li>
|
103
|
|
* <li>-reset</li>
|
104
|
|
* <li>-path [<path>]</li>
|
105
|
|
* <li>-setKeyValue <key> <value></li>
|
106
|
|
* <li>-removeKey <key></li>
|
107
|
|
* <li><i>(any additional arguments that are handled by a derived class)</i></li>
|
108
|
|
* </ul>
|
109
|
|
* The arguments are processed in the same sequence as they appear in the
|
110
|
|
* argument array.
|
111
|
|
*
|
112
|
|
* @param anArgs <i>(required)</i>.
|
113
|
|
*/
|
114
|
0
|
protected void doMain(String[] anArgs) {
|
115
|
0
|
String path = null;
|
116
|
0
|
try {
|
117
|
0
|
boolean operated = false;
|
118
|
0
|
for (int i = 0; i < anArgs.length; i++) {
|
119
|
0
|
String a = anArgs[i];
|
120
|
0
|
if ("-import".equals(a)) {
|
121
|
0
|
if (i + 1 >= anArgs.length) {
|
122
|
0
|
Console.err("missing import file name");
|
123
|
0
|
usage();
|
124
|
0
|
System.exit(-1);
|
125
|
|
}
|
126
|
0
|
InputStream is = new BufferedInputStream(new FileInputStream(new File(anArgs[++i])));
|
127
|
0
|
Preferences.importPreferences(is);
|
128
|
0
|
operated = true;
|
129
|
0
|
} else if ("-export".equals(a)) {
|
130
|
0
|
if (i + 1 >= anArgs.length) {
|
131
|
0
|
Console.err("missing export file name");
|
132
|
0
|
usage();
|
133
|
0
|
System.exit(-1);
|
134
|
|
}
|
135
|
0
|
OutputStream os = new BufferedOutputStream(new FileOutputStream(new File(anArgs[++i])));
|
136
|
0
|
getPrefs().exportSubtree(os);
|
137
|
0
|
operated = true;
|
138
|
0
|
} else if ("-setKeyValue".equals(a)) {
|
139
|
0
|
if (i + 2 >= anArgs.length) {
|
140
|
0
|
Console.err("missing parameters for setKeyValue");
|
141
|
0
|
usage();
|
142
|
0
|
System.exit(-1);
|
143
|
|
}
|
144
|
0
|
if (null == path) {
|
145
|
0
|
getPrefs(anArgs[++i]).put(anArgs[++i], anArgs[++i]);
|
146
|
|
} else {
|
147
|
0
|
getPrefs(path).put(anArgs[++i], anArgs[++i]);
|
148
|
|
}
|
149
|
0
|
operated = true;
|
150
|
0
|
} else if ("-removeKey".equals(a)) {
|
151
|
0
|
if (i + 1 >= anArgs.length) {
|
152
|
0
|
Console.err("missing parameters for removeKey");
|
153
|
0
|
usage();
|
154
|
0
|
System.exit(-1);
|
155
|
|
}
|
156
|
0
|
if (null == path) {
|
157
|
0
|
getPrefs().remove(anArgs[++i]);
|
158
|
|
} else {
|
159
|
0
|
getPrefs(path).remove(anArgs[++i]);
|
160
|
|
}
|
161
|
0
|
operated = true;
|
162
|
0
|
} else if ("-remove".equals(a)) {
|
163
|
0
|
getPrefs().removeNode();
|
164
|
0
|
myPreferences = null;
|
165
|
0
|
operated = true;
|
166
|
0
|
} else if ("-path".equals(a)) {
|
167
|
0
|
if ((i + 1 < anArgs.length) && !anArgs[i + 1].startsWith("-")) {
|
168
|
0
|
path = anArgs[++i];
|
169
|
|
} else {
|
170
|
0
|
path = null;
|
171
|
|
}
|
172
|
0
|
operated = true;
|
173
|
0
|
} else if ("-reset".equals(a)) {
|
174
|
0
|
resetPrefs();
|
175
|
0
|
operated = true;
|
176
|
|
} else {
|
177
|
0
|
int tmp = doAcceptArgument(anArgs, i);
|
178
|
0
|
if (tmp < 0) {
|
179
|
0
|
Console.err("unknown option: " + a);
|
180
|
0
|
usage();
|
181
|
0
|
System.exit(-1);
|
182
|
|
} else {
|
183
|
0
|
i = tmp;
|
184
|
|
}
|
185
|
|
}
|
186
|
|
}
|
187
|
0
|
if (!operated) {
|
188
|
0
|
Console.err("missing option(s)");
|
189
|
0
|
usage();
|
190
|
0
|
System.exit(-1);
|
191
|
|
}
|
192
|
|
} catch (Exception e) {
|
193
|
0
|
e.printStackTrace();
|
194
|
0
|
System.exit(-1);
|
195
|
|
}
|
196
|
|
}
|
197
|
|
|
198
|
|
/**
|
199
|
|
* Hook method that is called if the "reset" option is handled.
|
200
|
|
* Before the hook method is called the current preferences are removed and new
|
201
|
|
* preferences will be created on demand.
|
202
|
|
* <p>
|
203
|
|
* Subclasses should implement this method by setting default values for the
|
204
|
|
* various preferences. This enables one to first reset the preferences and
|
205
|
|
* then to export them. The exported preferences should contain enough structural
|
206
|
|
* information to allow manual editing, i.e. ideally all possible preference
|
207
|
|
* keys with default values are present.
|
208
|
|
* <p>
|
209
|
|
* The default implementation does nothing.
|
210
|
|
*/
|
211
|
0
|
protected void doResetPrefs() {}
|
212
|
|
|
213
|
|
/**
|
214
|
|
* Hook method to accept an argument. This hook method is called if an argument
|
215
|
|
* is not known to the base class.
|
216
|
|
* <p>
|
217
|
|
* The default implementation returns -1, indicating that it can not handle the
|
218
|
|
* argument.
|
219
|
|
*
|
220
|
|
* @param anArgs <i>(required)</i>. The argument array that was supplied
|
221
|
|
* to the {@link #doMain} method.
|
222
|
|
* @param anIndex The index of the argument in the argument array that has to
|
223
|
|
* be accept.
|
224
|
|
* @return The new index. A negative value indicates that the hook method
|
225
|
|
* could not handle the argument. If the hook method can handle the argument
|
226
|
|
* then it returns the index of the last argument in the argument array that
|
227
|
|
* was processed by the call. For example if the hook method accepts an
|
228
|
|
* argument with no additional parameters then the supplied index paramter
|
229
|
|
* "anIndex" is returned. If the hook method handled the argument
|
230
|
|
* with an additional parameter then the returned index is one more than the
|
231
|
|
* supplied index.
|
232
|
|
*/
|
233
|
0
|
protected int doAcceptArgument(String[] anArgs, int anIndex) {
|
234
|
0
|
return -1;
|
235
|
|
}
|
236
|
|
}
|
237
|
|
|