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