001 /*
002 * Copyright 2005,2009 Ivan SZKIBA
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.ini4j;
017
018 import java.io.IOException;
019 import java.io.InputStream;
020 import java.io.Reader;
021
022 import java.net.URL;
023
024 import java.util.prefs.AbstractPreferences;
025 import java.util.prefs.BackingStoreException;
026
027 public class IniPreferences extends AbstractPreferences
028 {
029
030 /** frequently used empty String array */
031 private static final String[] EMPTY = {};
032
033 /** underlaying <code>Ini</code> implementation */
034 private final Ini _ini;
035
036 /**
037 * Constructs a new preferences node on top of <code>Ini</code> instance.
038 *
039 * @param ini underlaying <code>Ini</code> instance
040 */
041 public IniPreferences(Ini ini)
042 {
043 super(null, "");
044 _ini = ini;
045 }
046
047 /**
048 * Constructs a new preferences node based on newly loaded <code>Ini</code> instance.
049 *
050 * This is just a helper constructor, to make simpler constructing <code>IniPreferences</code>
051 * directly from <code>Reader</code>.
052 *
053 * @param input the <code>Reader</code> containing <code>Ini</code> data
054 * @throws IOException if an I/O error occured
055 * @throws InvalidIniFormatException if <code>Ini</code> parsing error occured
056 */
057 public IniPreferences(Reader input) throws IOException, InvalidIniFormatException
058 {
059 super(null, "");
060 _ini = new Ini(input);
061 }
062
063 /**
064 * Constructs a new preferences node based on newly loaded <code>Ini</code> instance.
065 *
066 * This is just a helper constructor, to make simpler constructing <code>IniPreferences</code>
067 * directly from <code>InputStream</code>.
068 *
069 * @param input the <code>InputStream</code> containing <code>Ini</code> data
070 * @throws IOException if an I/O error occured
071 * @throws InvalidIniFormatException if <code>Ini</code> parsing error occured
072 */
073 public IniPreferences(InputStream input) throws IOException, InvalidIniFormatException
074 {
075 super(null, "");
076 _ini = new Ini(input);
077 }
078
079 /**
080 * Constructs a new preferences node based on newly loaded <code>Ini</code> instance.
081 *
082 * This is just a helper constructor, to make simpler constructing <code>IniPreferences</code>
083 * directly from <code>URL</code>.
084 *
085 * @param input the <code>URL</code> containing <code>Ini</code> data
086 * @throws IOException if an I/O error occured
087 * @throws InvalidIniFormatException if <code>Ini</code> parsing error occured
088 */
089 public IniPreferences(URL input) throws IOException, InvalidIniFormatException
090 {
091 super(null, "");
092 _ini = new Ini(input);
093 }
094
095 /**
096 * Provide access to underlaying {@link org.ini4j.Ini} implementation.
097 *
098 * @return <code>Ini</code> implementation
099 */
100 protected Ini getIni()
101 {
102 return _ini;
103 }
104
105 /**
106 * Implements the <CODE>getSpi</CODE> method as per the specification in
107 * {@link java.util.prefs.AbstractPreferences#getSpi(String)}.
108 *
109 * This implementation doesn't support this operation, so allways throws UnsupportedOperationException.
110 *
111 * @return if the value associated with the specified key at this preference node, or null if there is no association for this key, or the association cannot be determined at this time.
112 * @param key key to getvalue for
113 * @throws UnsupportedOperationException this implementation allways throws this exception
114 */
115 @Override protected String getSpi(String key) throws UnsupportedOperationException
116 {
117 throw new UnsupportedOperationException();
118 }
119
120 /**
121 * Implements the <CODE>childrenNamesSpi</CODE> method as per the specification in
122 * {@link java.util.prefs.AbstractPreferences#childrenNamesSpi()}.
123 * @return an array containing the names of the children of this preference node.
124 * @throws BackingStoreException if this operation cannot be completed due to a failure in the backing store, or inability to communicate with it.
125 */
126 @Override protected String[] childrenNamesSpi() throws BackingStoreException
127 {
128 return _ini.keySet().toArray(EMPTY);
129 }
130
131 /**
132 * Implements the <CODE>childSpi</CODE> method as per the specification in
133 * {@link java.util.prefs.AbstractPreferences#childSpi(String)}.
134 * @param name child name
135 * @return child node
136 */
137 @Override protected SectionPreferences childSpi(String name)
138 {
139 Ini.Section sec = _ini.get(name);
140 boolean isNew = sec == null;
141
142 if (isNew)
143 {
144 sec = _ini.add(name);
145 }
146
147 return new SectionPreferences(this, sec, isNew);
148 }
149
150 /**
151 * Implements the <CODE>flushSpi</CODE> method as per the specification in
152 * {@link java.util.prefs.AbstractPreferences#flushSpi()}.
153 *
154 * This implementation does nothing.
155 *
156 * @throws BackingStoreException if this operation cannot be completed due to a failure in the backing store, or inability to communicate with it.
157 */
158 @Override protected void flushSpi() throws BackingStoreException
159 {
160 assert true;
161 }
162
163 /**
164 * Implements the <CODE>keysSpi</CODE> method as per the specification in
165 * {@link java.util.prefs.AbstractPreferences#keysSpi()}.
166 *
167 * This implementation allways return an empty array.
168 *
169 * @return an empty array.
170 * @throws BackingStoreException if this operation cannot be completed due to a failure in the backing store, or inability to communicate with it.
171 */
172 @Override protected String[] keysSpi() throws BackingStoreException
173 {
174 return EMPTY;
175 }
176
177 /**
178 * Implements the <CODE>putSpi</CODE> method as per the specification in
179 * {@link java.util.prefs.AbstractPreferences#putSpi(String,String)}.
180 *
181 * This implementation doesn;t support this operation, so allways throws UnsupportedOperationException.
182 *
183 * @param key key to set value for
184 * @param value new value for key
185 * @throws UnsupportedOperationException this implementation allways throws this exception
186 */
187 @Override protected void putSpi(String key, String value) throws UnsupportedOperationException
188 {
189 throw new UnsupportedOperationException();
190 }
191
192 /**
193 * Implements the <CODE>removeNodeSpi</CODE> method as per the specification in
194 * {@link java.util.prefs.AbstractPreferences#removeNodeSpi()}.
195 *
196 * This implementation doesn;t support this operation, so allways throws UnsupportedOperationException.
197 * @throws UnsupportedOperationException this implementation allways throws this exception
198 * @throws BackingStoreException this implementation never throws this exception
199 */
200 @Override protected void removeNodeSpi() throws BackingStoreException, UnsupportedOperationException
201 {
202 throw new UnsupportedOperationException();
203 }
204
205 /**
206 * Implements the <CODE>removeSpi</CODE> method as per the specification in
207 * {@link java.util.prefs.AbstractPreferences#removeSpi(String)}.
208 * @param key key to remove
209 * @throws UnsupportedOperationException this implementation allways throws this exception
210 */
211 @Override protected void removeSpi(String key) throws UnsupportedOperationException
212 {
213 throw new UnsupportedOperationException();
214 }
215
216 /**
217 * Implements the <CODE>syncSpi</CODE> method as per the specification in
218 * {@link java.util.prefs.AbstractPreferences#syncSpi()}.
219 *
220 * This implementation does nothing.
221 *
222 * @throws BackingStoreException if this operation cannot be completed due to a failure in the backing store, or inability to communicate with it.
223 */
224 @Override protected void syncSpi() throws BackingStoreException
225 {
226 assert true;
227 }
228
229 protected class SectionPreferences extends AbstractPreferences
230 {
231
232 /** underlaying <code>Section</code> implementation */
233 private final Ini.Section _section;
234
235 /**
236 * Constructs a new SectionPreferences instance on top of Ini.Section instance.
237 *
238 * @param parent parent preferences node
239 * @parem section underlaying Ini.Section instance
240 * @param isNew indicate is this a new node or already existing one
241 */
242 SectionPreferences(IniPreferences parent, Ini.Section section, boolean isNew)
243 {
244 super(parent, section.getName());
245 _section = section;
246 newNode = isNew;
247 }
248
249 /**
250 * Implements the <CODE>flush</CODE> method as per the specification in
251 * {@link java.util.prefs.Preferences#flush()}.
252 *
253 * This implementation just call parent's <code>flush()</code> method.
254 *
255 * @throws BackingStoreException if this operation cannot be completed due to a failure in the backing store, or inability to communicate with it.
256 */
257 @Override public void flush() throws BackingStoreException
258 {
259 parent().flush();
260 }
261
262 /**
263 * Implements the <CODE>sync</CODE> method as per the specification in
264 * {@link java.util.prefs.Preferences#sync()}.
265 *
266 * This implementation just call parent's <code>sync()</code> method.
267 *
268 * @throws BackingStoreException if this operation cannot be completed due to a failure in the backing store, or inability to communicate with it.
269 */
270 @Override public void sync() throws BackingStoreException
271 {
272 parent().sync();
273 }
274
275 /**
276 * Implements the <CODE>getSpi</CODE> method as per the specification in
277 * {@link java.util.prefs.AbstractPreferences#getSpi(String)}.
278 * @return if the value associated with the specified key at this preference node, or null if there is no association for this key, or the association cannot be determined at this time.
279 * @param key key to getvalue for
280 */
281 @Override protected String getSpi(String key)
282 {
283 return _section.fetch(key);
284 }
285
286 /**
287 * Implements the <CODE>childrenNamesSpi</CODE> method as per the specification in
288 * {@link java.util.prefs.AbstractPreferences#childrenNamesSpi()}.
289 *
290 * This implementation allways returns an empty array.
291 *
292 * @return an emty array.
293 * @throws BackingStoreException if this operation cannot be completed due to a failure in the backing store, or inability to communicate with it.
294 */
295 @Override protected String[] childrenNamesSpi() throws BackingStoreException
296 {
297 return EMPTY;
298 }
299
300 /**
301 * Implements the <CODE>childSpi</CODE> method as per the specification in
302 * {@link java.util.prefs.AbstractPreferences#childSpi(String)}.
303 *
304 * This implementation doesn't support this operation.
305 *
306 * @throws UnsupportedOperationException this implementation allways throws this exception
307 * @param name child name
308 * @return child node
309 */
310 @Override protected IniPreferences childSpi(String name) throws UnsupportedOperationException
311 {
312 throw new UnsupportedOperationException();
313 }
314
315 /**
316 * Implements the <CODE>flushSpi</CODE> method as per the specification in
317 * {@link java.util.prefs.AbstractPreferences#flushSpi()}.
318 *
319 * This implementation does nothing.
320 *
321 * @throws BackingStoreException if this operation cannot be completed due to a failure in the backing store, or inability to communicate with it.
322 */
323 @Override protected void flushSpi() throws BackingStoreException
324 {
325 assert true;
326 }
327
328 /**
329 * Implements the <CODE>keysSpi</CODE> method as per the specification in
330 * {@link java.util.prefs.AbstractPreferences#keysSpi()}.
331 *
332 * @return an array of the keys that have an associated value in this preference node.
333 * @throws BackingStoreException if this operation cannot be completed due to a failure in the backing store, or inability to communicate with it.
334 */
335 @Override protected String[] keysSpi() throws BackingStoreException
336 {
337 return _section.keySet().toArray(EMPTY);
338 }
339
340 /**
341 * Implements the <CODE>putSpi</CODE> method as per the specification in
342 * {@link java.util.prefs.AbstractPreferences#putSpi(String,String)}.
343 *
344 * @param key key to set value for
345 * @param value new value of key
346 */
347 @Override protected void putSpi(String key, String value)
348 {
349 _section.put(key, value);
350 }
351
352 /**
353 * Implements the <CODE>removeNodeSpi</CODE> method as per the specification in
354 * {@link java.util.prefs.AbstractPreferences#removeNodeSpi()}.
355 *
356 * @throws BackingStoreException if this operation cannot be completed due to a failure in the backing store, or inability to communicate with it.
357 */
358 @Override protected void removeNodeSpi() throws BackingStoreException
359 {
360 _ini.remove(_section);
361 }
362
363 /**
364 * Implements the <CODE>removeSpi</CODE> method as per the specification in
365 * {@link java.util.prefs.AbstractPreferences#removeSpi(String)}.
366 * @param key key to remove
367 */
368 @Override protected void removeSpi(String key)
369 {
370 _section.remove(key);
371 }
372
373 /**
374 * Implements the <CODE>syncSpi</CODE> method as per the specification in
375 * {@link java.util.prefs.AbstractPreferences#syncSpi()}.
376 *
377 * This implementation does nothing.
378 *
379 * @throws BackingStoreException if this operation cannot be completed due to a failure in the backing store, or inability to communicate with it.
380 */
381 @Override protected void syncSpi() throws BackingStoreException
382 {
383 assert true;
384 }
385 }
386 }