001: /*
002: * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
003: *
004: * http://izpack.org/
005: * http://izpack.codehaus.org/
006: *
007: * Copyright 2005 Klaus Bartz
008: *
009: * Licensed under the Apache License, Version 2.0 (the "License");
010: * you may not use this file except in compliance with the License.
011: * You may obtain a copy of the License at
012: *
013: * http://www.apache.org/licenses/LICENSE-2.0
014: *
015: * Unless required by applicable law or agreed to in writing, software
016: * distributed under the License is distributed on an "AS IS" BASIS,
017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018: * See the License for the specific language governing permissions and
019: * limitations under the License.
020: */
021:
022: package com.coi.tools.os.win;
023:
024: import java.util.ArrayList;
025: import java.util.Iterator;
026: import java.util.List;
027:
028: /**
029: * System dependent helper for MS Windows registry handling. This class is only vaild on Windows. It
030: * declares naitve methods which are implemented in COIOSHelper.dll. The native methods uses the
031: * classes RegDataContainer and AccessControlList as in and output. Do not change the getter and
032: * setter methods of them. Do not try to implement a get or setValueACL because it will be nonsense.
033: * In the registry only keys have a ACL. not values.
034: *
035: * @author Klaus Bartz
036: */
037: public class RegistryImpl implements MSWinConstants {
038:
039: private static final String DEFAULT_PLACEHOLDER = "__#$&DEFAULT_PLACEHODER_VALUE#$?";
040:
041: private int currentRoot = HKEY_CURRENT_USER;
042:
043: private List logging = new ArrayList();
044:
045: private boolean doLogging = false;
046:
047: /**
048: * Creates a new empty RegistryImpl object.
049: */
050: public RegistryImpl() {
051: super ();
052: }
053:
054: /**
055: * Returns current root.
056: *
057: * @return current root
058: */
059: public int getRoot() {
060: return currentRoot;
061: }
062:
063: /**
064: * Sets the root id to the given value.
065: *
066: * @param i root id to be set
067: */
068: public void setRoot(int i) {
069: currentRoot = i;
070: }
071:
072: /**
073: * Returns the value of the given value name as RegDataContainer.
074: *
075: * @param key key of the registry entry
076: * @param value value name of the registry entry
077: * @return the value of the given value name as RegDataContainer
078: * @throws NativeLibException
079: */
080: public RegDataContainer getValue(String key, String value)
081: throws NativeLibException {
082: if (key == null)
083: key = "";
084: return (getValue(currentRoot, key, value));
085: }
086:
087: /**
088: * Returns the value of the given value name as Object. The real type depends to the type of the
089: * value.
090: *
091: * @param key key of the registry entry
092: * @param value value name of the registry entry
093: * @return the value of the given value name as RegDataContainer
094: * @throws NativeLibException
095: */
096: public Object getValueAsObject(String key, String value)
097: throws NativeLibException {
098: if (key == null)
099: key = "";
100: return (getValue(currentRoot, key, value).getDataAsObject());
101: }
102:
103: /**
104: * Returns all sub keys under the given key which is under the current root.
105: *
106: * @param key key for which the sub keys should be detected
107: * @return all sub keys under the given key which is under the current root
108: * @throws NativeLibException
109: */
110: public String[] getSubkeys(String key) throws NativeLibException {
111: if (key == null)
112: key = "";
113: return (getSubkeyNames(currentRoot, key));
114: }
115:
116: /**
117: * Returns all value names under the given key which is under the current root.
118: *
119: * @param key key for which the values should be detected
120: * @return all value names under the given key which is under the current root
121: * @throws NativeLibException
122: */
123: public String[] getValueNames(String key) throws NativeLibException {
124: if (key == null)
125: key = "";
126: return (getValueNames(currentRoot, key));
127: }
128:
129: /**
130: * Creates the given key under the current root.
131: *
132: * @param key key to be created
133: * @throws NativeLibException
134: */
135: public void createKey(String key) throws NativeLibException {
136: createKey(currentRoot, key);
137: }
138:
139: /**
140: * Creates the given key under the given root.
141: * It is possible to declare keys without a sub path.
142: * This is only possible on roots which are no real roots
143: * (e.g. HKEY_CURRENT_USER which is a link to
144: * HKEY_USERS\GUID of current user). Therefore this method
145: * will be raise an exception if root is a real root and
146: * key contains no sub path.
147: *
148: * @param root to be used
149: * @param key key to be created
150: * @throws NativeLibException
151: */
152: public void createKey(int root, String key)
153: throws NativeLibException {
154: int pathEnd = key.lastIndexOf('\\');
155: if (pathEnd > 0) {
156: String subkey = key.substring(0, pathEnd);
157: if (!exist(root, subkey)) { // Create missing sub keys
158: createKey(root, subkey);
159: }
160: }
161: // Create key
162: createKeyN(root, key);
163: RegistryLogItem rli = new RegistryLogItem(
164: RegistryLogItem.CREATED_KEY, root, key, null, null,
165: null);
166: log(rli);
167:
168: }
169:
170: /**
171: * Returns whether the given key under the current root exist or not.
172: *
173: * @param key key to be tested
174: * @return true if thekey exist, else false
175: * @throws NativeLibException
176: */
177: public boolean keyExist(String key) throws NativeLibException {
178: return (keyExist(currentRoot, key));
179: }
180:
181: /**
182: * Returns whether the given key under the given root exist or not.
183: *
184: * @param root to be used
185: * @param key key to be tested
186: * @return true if thekey exist, else false
187: * @throws NativeLibException
188: */
189: public boolean keyExist(int root, String key)
190: throws NativeLibException {
191: try {
192: return (exist(root, key));
193: } catch (NativeLibException ne) {
194: String em = ne.getLibMessage();
195: if ("functionFailed.RegOpenKeyEx".equals(em)) {
196: return (false);
197: }
198: throw (ne);
199: }
200: }
201:
202: /**
203: * Returns whether the given value exist under the current root or not.
204: *
205: * @param key key of the value for which should be tested
206: * @param value value to be tested
207: * @return true if the value exist, else false
208: * @throws NativeLibException
209: */
210: public boolean valueExist(String key, String value)
211: throws NativeLibException {
212: if (key == null)
213: key = "";
214: try {
215: this .getValue(currentRoot, key, value);
216: } catch (NativeLibException ne) {
217: String em = ne.getLibMessage();
218: if ("functionFailed.RegOpenKeyEx".equals(em)
219: || "functionFailed.RegQueryValueEx".equals(em)) {
220: return (false);
221: }
222: throw (ne);
223: }
224: return (true);
225: }
226:
227: /**
228: * Sets the given contents to the given registry value. If a sub key or the registry value does
229: * not exist, it will be created. REG_SZ is used as registry value type.
230: *
231: * @param key the registry key which should be used or created
232: * @param value the registry value into which the contents should be set
233: * @param contents the contents for the value
234: * @throws NativeLibException
235: */
236: public void setValue(String key, String value, String contents)
237: throws NativeLibException {
238:
239: setValue(currentRoot, key, value,
240: new RegDataContainer(contents));
241: }
242:
243: /**
244: * Sets the given contents to the given registry value. If a sub key or the registry value does
245: * not exist, it will be created. REG_MULTI_SZ is used as registry value type.
246: *
247: * @param key the registry key which should be used or created
248: * @param value the registry value into which the contents should be set
249: * @param contents the contents for the value
250: * @throws NativeLibException
251: */
252: public void setValue(String key, String value, String[] contents)
253: throws NativeLibException {
254:
255: setValue(currentRoot, key, value,
256: new RegDataContainer(contents));
257: }
258:
259: /**
260: * Sets the given contents to the given registry value. If a sub key or the registry value does
261: * not exist, it will be created. REG_BINARY is used as registry value type.
262: *
263: * @param key the registry key which should be used or created
264: * @param value the registry value into which the contents should be set
265: * @param contents the contents for the value
266: * @throws NativeLibException
267: */
268: public void setValue(String key, String value, byte[] contents)
269: throws NativeLibException {
270:
271: setValue(currentRoot, key, value,
272: new RegDataContainer(contents));
273: }
274:
275: /**
276: * Sets the given contents to the given registry value. If a sub key or the registry value does
277: * not exist, it will be created. REG_DWORD is used as registry value type.
278: *
279: * @param key the registry key which should be used or created
280: * @param value the registry value into which the contents should be set
281: * @param contents the contents for the value
282: * @throws NativeLibException
283: */
284: public void setValue(String key, String value, long contents)
285: throws NativeLibException {
286: setValue(currentRoot, key, value,
287: new RegDataContainer(contents));
288: }
289:
290: /**
291: * Sets the given contents to the given registry value under current root. If a sub key or the
292: * registry value does not exist, it will be created. The used registry value type will be
293: * determined by the type of the RegDataContainer.
294: *
295: * @param key the registry key which should be used or created
296: * @param value the registry value into which the contents should be set
297: * @param contents the contents for the value
298: * @throws NativeLibException
299: */
300: public void setValue(String key, String value,
301: RegDataContainer contents) throws NativeLibException {
302: setValue(currentRoot, key, value, contents);
303: }
304:
305: /**
306: * Sets the given contents to the given registry value. If a sub key or the registry value does
307: * not exist, it will be created. The used registry value type will be determined by the type of
308: * the RegDataContainer.
309: *
310: * @param root id for the root of the key
311: * @param key the registry key which should be used or created
312: * @param value the registry value into which the contents should be set
313: * @param contents the contents for the value
314: * @throws NativeLibException
315: */
316: public void setValue(int root, String key, String value,
317: RegDataContainer contents) throws NativeLibException {
318: RegDataContainer oldContents = null;
319: String localValue = value;
320: if (key == null)
321: key = "";
322: if (value == null) // We allow it for the default value...
323: value = "";
324: // May be someone do not like backslashes ...
325: key = key.replace('/', '\\');
326:
327: synchronized (logging) {
328: try {
329: oldContents = getValue(currentRoot, key, value);
330: } catch (NativeLibException ne) {
331: String em = ne.getLibMessage();
332: if ("functionFailed.RegOpenKeyEx".equals(em)
333: || "functionFailed.RegQueryValueEx".equals(em)) {
334: setValueR(root, key, value, contents);
335: return;
336: }
337: throw (ne);
338: }
339: setValueN(root, key, value, contents);
340: // Add value changing to log list
341: if (value.length() == 0) // The default value ...
342: localValue = DEFAULT_PLACEHOLDER; // Rewind will fail if last
343: // token is
344: // empty.
345:
346: RegistryLogItem rli = new RegistryLogItem(
347: RegistryLogItem.CHANGED_VALUE, root, key,
348: localValue, contents, oldContents);
349: log(rli);
350: }
351: }
352:
353: /**
354: * Deletes a key under the current root if exist and it is empty, else throw an exception.
355: *
356: * @param key key to be deleted
357: * @throws NativeLibException
358: */
359: public void deleteKey(String key) throws NativeLibException {
360: deleteKeyL(currentRoot, key);
361: }
362:
363: /**
364: * Deletes a key under the current root if it is empty, else do nothing.
365: *
366: * @param key key to be deleted
367: * @throws NativeLibException
368: */
369: public void deleteKeyIfEmpty(String key) throws NativeLibException {
370: deleteKeyIfEmpty(currentRoot, key);
371: }
372:
373: /**
374: * Deletes a key if it is empty, else do nothing.
375: *
376: * @param root id for the root of the key
377: * @param key key to be deleted
378: * @throws NativeLibException
379: */
380: public void deleteKeyIfEmpty(int root, String key)
381: throws NativeLibException {
382: if (keyExist(root, key) && isKeyEmpty(root, key))
383: deleteKeyL(root, key);
384:
385: }
386:
387: /**
388: * Deletes a value.
389: *
390: * @param key key of the value which should be deleted
391: * @param value value name to be deleted
392: * @throws NativeLibException
393: */
394: public void deleteValue(String key, String value)
395: throws NativeLibException {
396: deleteValueL(currentRoot, key, value);
397: }
398:
399: /**
400: * Deletes a key with logging.
401: *
402: * @param root id for the root of the key
403: * @param key key to be deleted
404: * @throws NativeLibException
405: */
406: private void deleteKeyL(int root, String key)
407: throws NativeLibException {
408: RegistryLogItem rli = new RegistryLogItem(
409: RegistryLogItem.REMOVED_KEY, root, key, null, null,
410: null);
411: log(rli);
412: deleteKeyN(root, key);
413: }
414:
415: /**
416: * Deletes a value with logging.
417: *
418: * @param root id for the root of the key
419: * @param key key of the value which should be deleted
420: * @param value value name to be deleted
421: * @throws NativeLibException
422: */
423: private void deleteValueL(int root, String key, String value)
424: throws NativeLibException {
425: if (key == null)
426: key = "";
427: RegDataContainer oldContents = getValue(currentRoot, key, value);
428: RegistryLogItem rli = new RegistryLogItem(
429: RegistryLogItem.REMOVED_VALUE, root, key, value, null,
430: oldContents);
431: log(rli);
432: deleteValueN(currentRoot, key, value);
433: }
434:
435: /**
436: * Rewinds all logged actions.
437: *
438: * @throws IllegalArgumentException
439: * @throws NativeLibException
440: */
441: public void rewind() throws IllegalArgumentException,
442: NativeLibException {
443: synchronized (logging) {
444: Iterator iter = logging.iterator();
445: suspendLogging();
446:
447: while (iter.hasNext()) {
448: RegistryLogItem rli = (RegistryLogItem) iter.next();
449: String rliValueName = (DEFAULT_PLACEHOLDER.equals(rli
450: .getValueName())) ? "" : rli.getValueName();
451: switch (rli.getType()) {
452: case RegistryLogItem.CREATED_KEY:
453: deleteKeyIfEmpty(rli.getRoot(), rli.getKey());
454: break;
455: case RegistryLogItem.REMOVED_KEY:
456: createKeyN(rli.getRoot(), rli.getKey());
457: break;
458: case RegistryLogItem.CREATED_VALUE:
459: RegDataContainer currentContents = null;
460: // Delete value only if reg entry exists and is equal to the stored value.
461: try {
462: currentContents = getValue(rli.getRoot(), rli
463: .getKey(), rliValueName);
464: } catch (NativeLibException nle) {
465: break;
466: }
467: if (currentContents.equals(rli.getNewValue())) {
468: deleteValueN(rli.getRoot(), rli.getKey(),
469: rliValueName);
470: }
471: // TODO: what todo if value has changed?
472: break;
473: case RegistryLogItem.REMOVED_VALUE:
474: // Set old value only if reg entry not exists.
475: try {
476: getValue(rli.getRoot(), rli.getKey(),
477: rliValueName);
478: } catch (NativeLibException nle) {
479: setValueN(rli.getRoot(), rli.getKey(),
480: rliValueName, rli.getOldValue());
481: }
482: break;
483: case RegistryLogItem.CHANGED_VALUE:
484: // Change to old value only if reg entry exists and equal to
485: // the
486: // stored value.
487: try {
488: currentContents = getValue(rli.getRoot(), rli
489: .getKey(), rliValueName);
490: } catch (NativeLibException nle) {
491: break;
492: }
493: if (currentContents.equals(rli.getNewValue())) {
494: setValueN(rli.getRoot(), rli.getKey(),
495: rliValueName, rli.getOldValue());
496: }
497: break;
498: }
499: }
500: }
501:
502: }
503:
504: /**
505: * Sets the given contents to the given registry value. If a sub key or the registry value does
506: * not exist, it will be created. The used registry value type will be determined by the type of
507: * the RegDataContainer.
508: *
509: * @param root id for the root of the key
510: * @param key the registry key which should be used or created
511: * @param value the registry value into which the contents should be set
512: * @param contents the contents for the value
513: * @throws NativeLibException
514: */
515: private void setValueR(int root, String key, String value,
516: RegDataContainer contents) throws NativeLibException {
517: String localValue = value;
518: if (!exist(root, key)) { // Create missing sub keys
519: createKey(root, key);
520: }
521: // Create value
522: setValueN(root, key, value, contents);
523: // Add value creation to log list
524: if (value.length() == 0) // The default value ...
525: localValue = DEFAULT_PLACEHOLDER; // Rewind will fail if last token
526: // is
527: // empty.
528: StringBuffer sb = new StringBuffer();
529: sb.append("SetValue;").append(Integer.toString(root)).append(
530: ";").append(key).append(";").append(localValue);
531: RegistryLogItem rli = new RegistryLogItem(
532: RegistryLogItem.CREATED_VALUE, root, key, localValue,
533: contents, null);
534: log(rli);
535: }
536:
537: private native boolean exist(int root, String key)
538: throws NativeLibException;
539:
540: private native void createKeyN(int root, String key)
541: throws NativeLibException;
542:
543: private native void setValueN(int root, String key, String value,
544: RegDataContainer contents) throws NativeLibException;
545:
546: private native RegDataContainer getValue(int root, String key,
547: String value) throws NativeLibException;
548:
549: private native void deleteValueN(int root, String key, String value)
550: throws NativeLibException;
551:
552: private native void deleteKeyN(int root, String key)
553: throws NativeLibException;
554:
555: private native boolean isKeyEmpty(int root, String key)
556: throws NativeLibException;
557:
558: private native String[] getSubkeyNames(int root, String key)
559: throws NativeLibException;
560:
561: private native String[] getValueNames(int root, String key)
562: throws NativeLibException;
563:
564: // Methods which are implemented in the native part but not used yet. To suppress warnings
565: // in Eclipse this methods are commented out. Comment in if needed.
566: // private native int getValueType(int root, String key, String value) throws
567: // NativeLibException;
568: //
569: // private native int getSubkeyCount(int root, String key) throws NativeLibException;
570: //
571: // private native int getValueCount(int root, String key) throws NativeLibException;
572: //
573: // private native String getSubkeyName(int root, String key, int index) throws
574: // NativeLibException;
575: //
576: // private native String getValueName(int root, String key, int index) throws
577: // NativeLibException;
578: //
579: // private native void modifyKeyACL(int root, String key, AccessControlList acl)
580: // throws NativeLibException;
581: //
582: // private native AccessControlList getKeyACL(int root, String key) throws NativeLibException;
583:
584: /**
585: * Creates a new (empty) logging list and activates logging.
586: */
587: public void resetLogging() {
588: logging = new ArrayList();
589: activateLogging();
590: }
591:
592: /**
593: * Suspends logging.
594: */
595: public void suspendLogging() {
596: doLogging = false;
597: }
598:
599: /**
600: * Activates logging.
601: */
602: public void activateLogging() {
603: doLogging = true;
604: }
605:
606: /**
607: * Returns a copy of the colected logging informations.
608: *
609: * @return a copy of the colected logging informations
610: */
611: public List<Object> getLoggingInfo() {
612: ArrayList<Object> retval = new ArrayList<Object>(logging.size());
613: Iterator iter = logging.iterator();
614: while (iter.hasNext())
615: try {
616: retval.add(((RegistryLogItem) iter.next()).clone());
617: } catch (CloneNotSupportedException e) { // Should never be...
618: e.printStackTrace();
619: }
620: return (retval);
621: }
622:
623: /**
624: * Copies the contents of the given list of RegistryLogItems to a newly created internal logging
625: * list.
626: *
627: * @param info list containing RegistryLogItems to be used for logging
628: */
629: public void setLoggingInfo(List info) {
630: resetLogging();
631: addLoggingInfo(info);
632: }
633:
634: /**
635: * Adds copies of the contents of the given list of RegistryLogItems to the existent internal
636: *
637: * @param info list containing RegistryLogItems to be used for logging logging list.
638: */
639: public void addLoggingInfo(List info) {
640: Iterator iter = info.iterator();
641: while (iter.hasNext())
642: try {
643: logging.add(((RegistryLogItem) iter.next()).clone());
644: } catch (CloneNotSupportedException e) { // Should never be
645: e.printStackTrace();
646: }
647:
648: }
649:
650: /**
651: * Adds the given item to the beginning of the logging list if logging is enabled, else do
652: * nothing.
653: *
654: * @param item
655: */
656: private void log(RegistryLogItem item) {
657: if (doLogging && logging != null)
658: logging.add(0, item);
659: }
660:
661: }
|