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 }