001: /*
002: ** Java native interface to the Windows Registry API.
003: ** Copyright (c) 1997 by Timothy Gerard Endres
004: **
005: ** This program is free software.
006: **
007: ** You may redistribute it and/or modify it under the terms of the GNU
008: ** General Public License as published by the Free Software Foundation.
009: ** Version 2 of the license should be included with this distribution in
010: ** the file LICENSE, as well as License.html. If the license is not
011: ** included with this distribution, you may find a copy at the FSF web
012: ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the
013: ** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA.
014: **
015: ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
016: ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
017: ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
018: ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
019: ** REDISTRIBUTION OF THIS SOFTWARE.
020: **
021: */
022:
023: package com.ice.jni.registry;
024:
025: import java.io.PrintWriter;
026: import java.util.*;
027:
028: /**
029: * The RegistryKey class represents a key in the registry.
030: * The class also provides all of the native interface calls.
031: *
032: * You should refer to the Windows Registry API documentation
033: * for the details of any of the native methods. The native
034: * implementation performs almost no processing before or after
035: * a given call, so their behavior should match the API's
036: * documented behavior precisely.
037: *
038: * Note that you can not open a subkey without an existing
039: * open RegistryKey. Thus, you need to start with one of the
040: * top level keys defined in the Registry class and open
041: * relative to that.
042: *
043: * @see com.ice.jni.registry.Registry
044: * @see com.ice.jni.registry.RegistryValue
045: */
046:
047: public class RegistryKey {
048: /**
049: * Constants used to determine the access level for
050: * newly opened keys.
051: */
052: public static final int ACCESS_DEFAULT = 0;
053: public static final int ACCESS_READ = 1;
054: public static final int ACCESS_WRITE = 2;
055: public static final int ACCESS_EXECUTE = 3;
056: public static final int ACCESS_ALL = 4;
057:
058: /**
059: * This is the actual DWORD key that is returned from the
060: * Registry API. This value is <strong>totally opaque</strong>
061: * and should never be referenced.
062: */
063: protected int hKey;
064:
065: /**
066: * The full pathname of this key.
067: */
068: protected String name;
069:
070: /**
071: * Used to indicate whether or not the key was created
072: * when method createSubKey() is called, otherwise false.
073: */
074: protected boolean created;
075:
076: public RegistryKey(int hKey, String name) {
077: this .hKey = hKey;
078: this .name = name;
079: this .created = false;
080: }
081:
082: public RegistryKey(int hKey, String name, boolean created) {
083: this .hKey = hKey;
084: this .name = name;
085: this .created = created;
086: }
087:
088: /**
089: * The finalize() override checks to be sure the key is closed.
090: */
091: public void finalize() {
092: // Never close a top level key...
093: if (this .name.indexOf("\\") > 0) {
094: // REVIEW should we have an "open/closed" flag
095: // to avoid double closes? Or is it better to
096: // lazily not call closeKey() and let finalize()
097: // do it all the time?
098: //
099: try {
100: this .closeKey();
101: } catch (RegistryException ex) {
102: }
103: }
104: }
105:
106: /**
107: * Get the name of this key. This is <em>not</em> fully
108: * qualified, which means that the name will not contain
109: * any backslashes.
110: *
111: * @return The relative name of this key.
112: */
113:
114: public String getName() {
115: int index = this .name.lastIndexOf("\\");
116:
117: if (index < 0)
118: return this .name;
119: else
120: return this .name.substring(index + 1);
121: }
122:
123: /**
124: * Get the full name of the key, from the top level down.
125: *
126: * @return The full name of the key.
127: */
128:
129: public String getFullName() {
130: return this .name;
131: }
132:
133: /**
134: * Determine if this key was opened or created and opened.
135: * The result can only be true if createSubKey() was called
136: * and the key did not exist, and the creation of the new
137: * subkey succeeded.
138: *
139: * @return True if the key was created new, else false.
140: */
141:
142: public boolean wasCreated() {
143: return this .created;
144: }
145:
146: /**
147: * Used to set the <em>created</em> state of this key.
148: *
149: * @param created The new <em>created</em> state.
150: */
151:
152: public void setCreated(boolean created) {
153: this .created = created;
154: }
155:
156: /**
157: * Open a Registry subkey of this key with READ access.
158: *
159: * @param subkey The name of the subkey to open.
160: * @return The newly opened RegistryKey.
161: *
162: * @exception NoSuchKeyException If the subkey does not exist.
163: * @exception RegistryException Any other registry API error.
164: */
165:
166: public RegistryKey openSubKey(String subkey)
167: throws NoSuchKeyException, RegistryException {
168: return this .openSubKey(subkey, ACCESS_READ);
169: }
170:
171: /**
172: * Create, and open, a Registry subkey of this key with WRITE access.
173: * If the key already exists, it is opened, otherwise it is first
174: * created and then opened.
175: *
176: * @param subkey The name of the subkey to create.
177: * @param className The className of the created subkey.
178: * @return The newly created and opened RegistryKey.
179: *
180: * @exception RegistryException Any valid registry API error.
181: */
182:
183: public RegistryKey createSubKey(String subkey, String className)
184: throws RegistryException {
185: return this .openSubKey(subkey, ACCESS_WRITE);
186: }
187:
188: /**
189: * Set the value of this RegistryKey.
190: *
191: * @param value The value to set, including the value name.
192: *
193: * @exception RegistryException Any valid registry API error.
194: */
195:
196: public void setValue(RegistryValue value) throws RegistryException {
197: this .setValue(value.getName(), value);
198: }
199:
200: //
201: // N A T I V E M E T H O D S
202: //
203:
204: /**
205: * Open a Registry subkey of this key with the specified access.
206: *
207: * @param subkey The name of the subkey to open.
208: * @param access The access level for the open.
209: * @return The newly opened RegistryKey.
210: *
211: * @exception NoSuchKeyException If the subkey does not exist.
212: * @exception RegistryException Any other registry API error.
213: */
214:
215: public native RegistryKey openSubKey(String subKey, int access)
216: throws NoSuchKeyException, RegistryException;
217:
218: /**
219: * Connect to the remote registry on <em>hostName</em>.
220: * This method will only work when invoked on a toplevel
221: * key. The returned value will be the same toplevel key
222: * opened from the remote host's registry.
223: *
224: * @param hostName The remote computer's hostname.
225: * @return The remote top level key identical to this top level key.
226: *
227: * @exception NoSuchKeyException If the subkey does not exist.
228: * @exception RegistryException Any other registry API error.
229: */
230: public native RegistryKey connectRegistry(String hostName)
231: throws NoSuchKeyException, RegistryException;
232:
233: /**
234: * Create a new subkey, or open the existing one. You can
235: * determine if the subkey was created, or whether an
236: * existing subkey was opened, via the wasCreated() method.
237: *
238: * @param subKey The name of the subkey to create/open.
239: * @param className The key's class name, or null.
240: * @param access The access level of the opened subkey.
241: * @return The newly created or opened subkey.
242: *
243: * @exception RegistryException Any valid registry API error.
244: */
245:
246: public native RegistryKey createSubKey(String subKey,
247: String className, int access) throws RegistryException;
248:
249: /**
250: * Closes this subkey. You may chose to let the finalize()
251: * method do the close.
252: *
253: * @exception RegistryException Any valid registry API error.
254: */
255:
256: public native void closeKey() throws RegistryException;
257:
258: /**
259: * Delete a named subkey.
260: *
261: * @param subKey The name of the subkey to delete.
262: *
263: * @exception NoSuchKeyException If the subkey does not exist.
264: * @exception RegistryException Any other registry API error.
265: */
266:
267: public native void deleteSubKey(String subKey)
268: throws NoSuchKeyException, RegistryException;
269:
270: /**
271: * Delete a named value.
272: *
273: * @param valueName The name of the value to delete.
274: *
275: * @exception NoSuchValueException If the value does not exist.
276: * @exception RegistryException Any other registry API error.
277: */
278:
279: public native void deleteValue(String valueName)
280: throws NoSuchValueException, RegistryException;
281:
282: /**
283: * Guarentees that this key is written to disk. This
284: * method should be called only when needed, as it has
285: * a huge performance cost.
286: *
287: * @exception RegistryException Any valid registry API error.
288: */
289:
290: public native void flushKey() throws RegistryException;
291:
292: /**
293: * Set the name value to the given data.
294: *
295: * @param valueName The name of the value to set.
296: * @param value The data to set the named value.
297: *
298: * @exception RegistryException Any valid registry API error.
299: */
300:
301: public native void setValue(String valueName, RegistryValue value)
302: throws RegistryException;
303:
304: /**
305: * Get the data of a named value.
306: *
307: * @param valueName The name of the value to get.
308: * @return The data of the named value.
309: *
310: * @exception NoSuchValueException If the value does not exist.
311: * @exception RegistryException Any other registry API error.
312: */
313:
314: public native RegistryValue getValue(String valueName)
315: throws NoSuchValueException, RegistryException;
316:
317: /**
318: * Get the value of a REG_SZ or REG_EXPAND_SZ value.
319: *
320: * @param valueName The name of the value to get.
321: * @return The string data of the named value.
322: *
323: * @exception NoSuchValueException If the value does not exist.
324: * @exception RegistryException Any other registry API error.
325: */
326:
327: public native String getStringValue(String valueName)
328: throws NoSuchValueException, RegistryException;
329:
330: /**
331: * Get the data from the default value.
332: *
333: * @return The string data of the default value.
334: *
335: * @exception NoSuchValueException If the value does not exist.
336: * @exception RegistryException Any other registry API error.
337: */
338:
339: public native String getDefaultValue() throws NoSuchValueException,
340: RegistryException;
341:
342: /**
343: * Determines if this key has a default value.
344: *
345: * @return True if there is a default value, else false.
346: *
347: * @exception RegistryException Any valid registry API error.
348: */
349:
350: public native boolean hasDefaultValue() throws RegistryException;
351:
352: /**
353: * Determines if this key has <em>only</em> a default value.
354: *
355: * @return True if there is only a default value, else false.
356: *
357: * @exception RegistryException Any valid registry API error.
358: */
359:
360: public native boolean hasOnlyDefaultValue()
361: throws RegistryException;
362:
363: /**
364: * Obtains the number of subkeys that this key contains.
365: *
366: * @return The number of subkeys that this key contains.
367: *
368: * @exception RegistryException Any valid registry API error.
369: */
370:
371: public native int getNumberSubkeys() throws RegistryException;
372:
373: /**
374: * Obtains the maximum length of all of the subkey names.
375: *
376: * @return The maximum length of all of the subkey names.
377: *
378: * @exception RegistryException Any valid registry API error.
379: */
380:
381: public native int getMaxSubkeyLength() throws RegistryException;
382:
383: /**
384: * Obtains an enumerator for the subkeys of this key.
385: *
386: * @return The key enumerator.
387: *
388: * @exception RegistryException Any valid registry API error.
389: */
390:
391: public native String regEnumKey(int index) throws RegistryException;
392:
393: /**
394: * Obtains the number of values that this key contains.
395: *
396: * @return The number of values that this key contains.
397: *
398: * @exception RegistryException Any valid registry API error.
399: */
400:
401: public native int getNumberValues() throws RegistryException;
402:
403: /**
404: * Obtains the maximum length of all of the value data.
405: *
406: * @return The maximum length of all of the value data.
407: *
408: * @exception RegistryException Any valid registry API error.
409: */
410:
411: public native int getMaxValueDataLength() throws RegistryException;
412:
413: /**
414: * Obtains the maximum length of all of the value names.
415: *
416: * @return The maximum length of all of the value names.
417: *
418: * @exception RegistryException Any valid registry API error.
419: */
420:
421: public native int getMaxValueNameLength() throws RegistryException;
422:
423: /**
424: * Obtains an enumerator for the values of this key.
425: *
426: * @return The value enumerator.
427: *
428: * @exception RegistryException Any valid registry API error.
429: */
430:
431: public native String regEnumValue(int index)
432: throws RegistryException;
433:
434: //
435: // Convenience routines
436: //
437:
438: /**
439: * This method will increment the value of a REG_DWORD value.
440: *
441: * @param valueName The name of the value to increment.
442: *
443: * @exception NoSuchValueException If the value does not exist.
444: * @exception RegistryException Any other registry API error.
445: */
446:
447: public native int incrDoubleWord(String valueName)
448: throws NoSuchValueException, RegistryException;
449:
450: /**
451: * This method will decrement the value of a REG_DWORD value.
452: *
453: * @param valueName The name of the value to increment.
454: *
455: * @exception NoSuchValueException If the value does not exist.
456: * @exception RegistryException Any other registry API error.
457: */
458:
459: public native int decrDoubleWord(String valueName)
460: throws NoSuchValueException, RegistryException;
461:
462: /**
463: * This method will expand a string to include the definitions
464: * of System environment variables that are referenced via the
465: * %variable% construct. This method invokes EnvExpandStrings().
466: *
467: * @param valueName The name of the value to increment.
468: */
469:
470: public static native String expandEnvStrings(String exString);
471:
472: /**
473: * Returns a new Enumeration that will enumerate the
474: * names of the subkeys of this key,
475: *
476: * @return A new Enumeration to enumerate subkey names.
477: *
478: * @exception RegistryException Any valid registry API error.
479: */
480:
481: public Enumeration keyElements() throws RegistryException {
482: return this .new RegistryKeyEnumerator(this );
483: }
484:
485: /**
486: * Returns a new Enumeration that will enumerate the
487: * names of the values of this key,
488: *
489: * @return A new Enumeration to enumerate value names.
490: *
491: * @exception RegistryException Any valid registry API error.
492: */
493:
494: public Enumeration valueElements() throws RegistryException {
495: return this .new RegistryValueEnumerator(this );
496: }
497:
498: /**
499: * A RegistryKey enumerator class. This enumerator
500: * is used to enumerate the names of this key's subkeys.
501: *
502: * This class should remain opaque to the client,
503: * which will use the Enumeration interface.
504: */
505: class RegistryKeyEnumerator implements Enumeration {
506: RegistryKey key;
507: int currIndex;
508: int numSubKeys;
509:
510: public RegistryKeyEnumerator(RegistryKey key)
511: throws RegistryException {
512: this .key = key;
513: this .currIndex = 0;
514: this .numSubKeys = key.getNumberSubkeys();
515: }
516:
517: public boolean hasMoreElements() {
518: return (this .currIndex < this .numSubKeys);
519: }
520:
521: public Object nextElement() {
522: Object result = null;
523:
524: try {
525: result = this .key.regEnumKey(this .currIndex++);
526: } catch (RegistryException ex) {
527: throw new NoSuchElementException(ex.getMessage());
528: }
529:
530: return result;
531: }
532: }
533:
534: /**
535: * A RegistryValue enumerator class. This enumerator
536: * is used to enumerate the names of this key's values.
537: * This will return the default value name as an empty string.
538: *
539: * This class should remain opaque to the client.
540: * It will use the Enumeration interface.
541: */
542:
543: class RegistryValueEnumerator implements Enumeration {
544: RegistryKey key;
545: int currIndex;
546: int numValues;
547:
548: public RegistryValueEnumerator(RegistryKey key)
549: throws RegistryException {
550: this .key = key;
551: this .currIndex = 0;
552: this .numValues = key.getNumberValues();
553: }
554:
555: public boolean hasMoreElements() {
556: return (this .currIndex < this .numValues);
557: }
558:
559: public Object nextElement() {
560: Object result = null;
561:
562: try {
563: result = this .key.regEnumValue(this .currIndex++);
564: } catch (RegistryException ex) {
565: throw new NoSuchElementException(ex.getMessage());
566: }
567:
568: return result;
569: }
570: }
571:
572: /**
573: * Export this key's definition to the provided PrintWriter.
574: * The resulting file can be imported via RegEdit.
575: *
576: * @exception NoSuchKeyException Thrown by openSubKey().
577: * @exception NoSuchValueException Thrown by getValue().
578: * @exception RegistryException Any other registry API error.
579: */
580:
581: public void
582: export( PrintWriter out, boolean descend )
583: throws NoSuchKeyException, RegistryException
584: {
585: Enumeration enum;
586:
587: out.println( "[" + this.getFullName() + "]" );
588:
589: enum = this.valueElements();
590:
591: for ( int idx = 0 ; enum.hasMoreElements() ; ++idx )
592: {
593: String valueName = (String) enum.nextElement();
594:
595: RegistryValue value = this.getValue( valueName );
596:
597: value.export( out );
598: }
599:
600: out.println( "" );
601:
602: if ( descend )
603: {
604: enum = this.keyElements();
605:
606: for ( int idx = 0 ; enum.hasMoreElements() ; ++idx )
607: {
608: String keyName = (String) enum.nextElement();
609:
610: RegistryKey subKey = this.openSubKey( keyName );
611:
612: subKey.export( out, descend );
613:
614: subKey.closeKey();
615: }
616: }
617: }
618: }
|