1 /* NodeWriter - Writes and exports preferences nodes to files 2 Copyright (C) 2001, 2006 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 package gnu.java.util.prefs; 39 40 import gnu.java.lang.CPStringBuilder; 41 42 import java.io.BufferedWriter; 43 import java.io.IOException; 44 import java.io.OutputStream; 45 import java.io.OutputStreamWriter; 46 import java.io.UnsupportedEncodingException; 47 import java.io.Writer; 48 49 import java.util.StringTokenizer; 50 51 import java.util.prefs.*; 52 53 /** 54 * Writes and exports preferences nodes to files 55 * 56 * @author Mark Wielaard (mark@klomp.org) 57 */ 58 public class NodeWriter { 59 60 /** The Preferences node to write. */ 61 private final Preferences prefs; 62 63 /** The bufferedWriter to write the node to. */ 64 private final BufferedWriter bw; 65 66 /** 67 * True if the complete sub tree should be written, 68 * false if only the node should be written. 69 */ 70 private boolean subtree; 71 72 /** 73 * Creates a new NodeWriter for the given preferences node and 74 * outputstream. Creates a new OutputStreamWriter. 75 */ NodeWriter(Preferences prefs, OutputStream os)76 public NodeWriter(Preferences prefs, OutputStream os) { 77 this.prefs = prefs; 78 Writer w; 79 try 80 { 81 w = new OutputStreamWriter(os, "UTF-8"); 82 } 83 catch (UnsupportedEncodingException uee) 84 { 85 // Shouldn't happen, since we always have UTF-8 available. 86 InternalError ie = new InternalError("UTF-8 encoding missing"); 87 ie.initCause(uee); 88 throw ie; 89 } 90 this.bw = new BufferedWriter(w); 91 } 92 93 /** 94 * Writes the preference node plus the complete subtree. 95 */ writePrefsTree()96 public void writePrefsTree() throws BackingStoreException, IOException { 97 subtree = true; 98 writeHeader(); 99 writePreferences(); 100 bw.flush(); 101 } 102 103 /** 104 * Writes only the preference node. 105 */ writePrefs()106 public void writePrefs() throws BackingStoreException, IOException { 107 subtree = false; 108 writeHeader(); 109 writePreferences(); 110 bw.flush(); 111 } 112 113 /** 114 * Writes the standard header. 115 */ writeHeader()116 private void writeHeader() throws BackingStoreException, IOException { 117 bw.write("<?xml version=\"1.0\"?>"); 118 bw.newLine(); 119 bw.write("<!DOCTYPE preferences SYSTEM " 120 + "\"http://java.sun.com/dtd/preferences.dtd\">"); 121 bw.newLine(); 122 bw.newLine(); 123 bw.write("<!-- GNU Classpath java.util.prefs Preferences "); 124 125 if (prefs.isUserNode()) { 126 bw.write("user"); 127 } else { 128 bw.write("system"); 129 } 130 131 // root node? 132 if (prefs.parent() == null) { 133 bw.write(" root"); 134 } 135 136 if (subtree) { 137 bw.write(" tree"); 138 } else { 139 bw.write(" node"); 140 } 141 142 // no root? 143 if (prefs.parent() != null) { 144 bw.newLine(); 145 bw.write(" '"); 146 bw.write(prefs.absolutePath()); 147 bw.write('\''); 148 bw.newLine(); 149 } 150 bw.write(" -->"); 151 bw.newLine(); 152 bw.newLine(); 153 } 154 155 /** 156 * Write the preferences tag and the root. 157 */ writePreferences()158 private void writePreferences() throws BackingStoreException, IOException { 159 bw.write("<preferences>"); 160 bw.newLine(); 161 writeRoot(); 162 bw.write("</preferences>"); 163 bw.newLine(); 164 } 165 writeRoot()166 private void writeRoot() throws BackingStoreException, IOException { 167 bw.write(" <root type=\""); 168 if (prefs.isUserNode()) { 169 bw.write("user"); 170 } else { 171 bw.write("system"); 172 } 173 bw.write("\">"); 174 175 writeRootMap(); 176 writeNode(); 177 178 bw.write(" </root>"); 179 bw.newLine(); 180 } 181 writeRootMap()182 private void writeRootMap() throws BackingStoreException, IOException { 183 // Is it a root node? 184 if(prefs.parent() == null && prefs.keys().length > 0) { 185 bw.newLine(); 186 writeMap(prefs, 2); 187 } else { 188 bw.write("<map/>"); 189 bw.newLine(); 190 } 191 } 192 193 /** 194 * Writes all the parents of the preferences node without any entries. 195 * Returns the number of parents written, which has to be used as 196 * argument to <code>writeCloseParents()</code> after writing the node 197 * itself. 198 */ writeParents()199 private int writeParents() throws IOException { 200 int parents; 201 String path = prefs.absolutePath(); 202 int lastslash = path.lastIndexOf("/"); 203 if (lastslash > 0) { 204 path = path.substring(1, lastslash); 205 StringTokenizer st = new StringTokenizer(path); 206 parents = st.countTokens(); 207 208 for (int i=0; i<parents; i++) { 209 String name = st.nextToken(); 210 indent(i+2); 211 bw.write("<node name=\"" + name + "\">"); 212 bw.write("<map/>"); 213 bw.write("</node>"); 214 bw.newLine(); 215 } 216 } else { 217 parents = 0; 218 } 219 220 return parents; 221 } 222 writeCloseParents(int parents)223 private void writeCloseParents(int parents) throws IOException { 224 while(parents > 0) { 225 indent(parents+1); 226 bw.write("</node>"); 227 bw.newLine(); 228 parents--; 229 } 230 } 231 writeNode()232 private void writeNode() throws BackingStoreException, IOException { 233 int parents = writeParents(); 234 // root? 235 int indent; 236 if (prefs.parent() == null) { 237 indent = parents+1; 238 } else { 239 indent = parents+2; 240 } 241 writeNode(prefs, indent); 242 writeCloseParents(parents); 243 } 244 writeNode(Preferences node, int indent)245 private void writeNode(Preferences node, int indent) 246 throws BackingStoreException, IOException 247 { 248 // not root? 249 if (node.parent() != null) { 250 indent(indent); 251 bw.write("<node name=\"" + node.name() + "\">"); 252 if (node.keys().length > 0) { 253 bw.newLine(); 254 } 255 writeMap(node, indent+1); 256 } 257 258 if (subtree) { 259 String[] children = node.childrenNames(); 260 for (int i=0; i<children.length; i++) { 261 Preferences child = node.node(children[i]); 262 writeNode(child, indent+1); 263 } 264 } 265 266 // not root? 267 if (node.parent() != null) { 268 indent(indent); 269 bw.write("</node>"); 270 bw.newLine(); 271 } 272 } 273 writeMap(Preferences node, int indent)274 private void writeMap(Preferences node, int indent) 275 throws BackingStoreException, IOException 276 { 277 // construct String used for indentation 278 CPStringBuilder indentBuffer = new CPStringBuilder(2*indent); 279 for (int i=0; i < indent; i++) 280 indentBuffer.append(" "); 281 String indentString = indentBuffer.toString(); 282 283 if (node.keys().length > 0) { 284 bw.write(indentString); 285 bw.write("<map>"); 286 bw.newLine(); 287 writeEntries(node, indentString + " "); 288 bw.write(indentString); 289 bw.write("</map>"); 290 } else { 291 bw.write("<map/>"); 292 } 293 bw.newLine(); 294 } 295 writeEntries(Preferences node, String indent)296 private void writeEntries(Preferences node, String indent) 297 throws BackingStoreException, IOException 298 { 299 String[] keys = node.keys(); 300 for(int i = 0; i < keys.length; i++) { 301 String value = node.get(keys[i], null); 302 if (value == null) { 303 throw new BackingStoreException("null value for key '" 304 + keys[i] + "'"); 305 } 306 307 bw.write(indent); 308 bw.write("<entry key=\"" + keys[i] + "\"" 309 + " value=\"" + value + "\"/>"); 310 bw.newLine(); 311 } 312 } 313 indent(int x)314 private void indent(int x) throws IOException { 315 for (int i=0; i<x; i++) { 316 bw.write(" "); 317 } 318 } 319 } 320