1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
// Copyright (C) 2001-2003 Jon A. Maxwell (JAM)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
package net.sourceforge.jnlp.util;
import net.sourceforge.jnlp.util.logging.OutputController;
import java.io.*;
import java.util.*;
/**
* A properties object backed by a specified file without throwing
* exceptions. The properties are automatically loaded from the
* file when the first property is requested, but the save method
* must be called before changes are saved to the file.<p>
*
* @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
* @version $Revision: 1.4 $
*/
public class PropertiesFile extends Properties {
/** the file to save to */
File file;
/** the header string */
String header = "netx file";
/** time of last modification, lazy loaded on getProperty */
long lastStore;
/**
* Create a properties object backed by the specified file.
*
* @param file the file to save and load to
*/
public PropertiesFile(File file) {
this.file = file;
}
/**
* Create a properties object backed by the specified file.
*
* @param file the file to save and load to
* @param header the file header
*/
public PropertiesFile(File file, String header) {
this.file = file;
this.header = header;
}
/**
* Returns the value of the specified key, or null if the key
* does not exist.
*/
public String getProperty(String key) {
if (lastStore == 0)
load();
return super.getProperty(key);
}
/**
* Returns the value of the specified key, or the default value
* if the key does not exist.
*/
public String getProperty(String key, String defaultValue) {
if (lastStore == 0)
load();
return super.getProperty(key, defaultValue);
}
/**
* Sets the value for the specified key.
*
* @return the previous value
*/
public Object setProperty(String key, String value) {
if (lastStore == 0)
load();
return super.setProperty(key, value);
}
/**
* Returns the file backing this properties object.
*/
public File getStoreFile() {
return file;
}
/**
* Ensures that the file backing these properties has been
* loaded; call this method before calling any method defined by
* a superclass.
*
* @return true, if file was (re-)loaded
* false, if file was still current
*/
public boolean load() {
if (!file.exists()) {
return false;
}
long currentStore = file.lastModified();
long currentTime = System.currentTimeMillis();
/* (re)load file, if
* - it wasn't loaded/stored, yet (lastStore == 0)
* - current file modification timestamp has changed since last store (currentStore != lastStore) OR
* - current file modification timestamp has not changed since last store AND current system time equals current file modification timestamp
* This is necessary because some filesystems seems only to provide accuracy of the timestamp on the level of seconds!
*/
if(lastStore == 0 || currentStore != lastStore || (currentStore == lastStore && currentStore / 1000 == currentTime / 1000)) {
InputStream s = null;
try {
try {
s = new FileInputStream(file);
load(s);
} finally {
if (s != null) {
s.close();
lastStore=currentStore;
return true;
}
}
} catch (IOException ex) {
OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
}
}
return false;
}
/**
* Saves the properties to the file.
*/
public void store() {
FileOutputStream s = null;
try {
try {
file.getParentFile().mkdirs();
s = new FileOutputStream(file);
store(s, header);
// fsync()
s.getChannel().force(true);
lastStore = file.lastModified();
} finally {
if (s != null) s.close();
}
} catch (IOException ex) {
OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
}
}
}
|