Frames | No Frames |
1: /* ======================================================================== 2: * JCommon : a free general purpose class library for the Java(tm) platform 3: * ======================================================================== 4: * 5: * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. 6: * 7: * Project Info: http://www.jfree.org/jcommon/index.html 8: * 9: * This library is free software; you can redistribute it and/or modify it 10: * under the terms of the GNU Lesser General Public License as published by 11: * the Free Software Foundation; either version 2.1 of the License, or 12: * (at your option) any later version. 13: * 14: * This library is distributed in the hope that it will be useful, but 15: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 17: * License for more details. 18: * 19: * You should have received a copy of the GNU Lesser General Public 20: * License along with this library; if not, write to the Free Software 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 22: * USA. 23: * 24: * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 25: * in the United States and other countries.] 26: * 27: * ------------------------------ 28: * SortedConfigurationWriter.java 29: * ------------------------------ 30: * (C)opyright 2003, 2004, by Thomas Morgner and Contributors. 31: * 32: * Original Author: Thomas Morgner; 33: * Contributor(s): -; 34: * 35: * $Id: SortedConfigurationWriter.java,v 1.4 2005/11/03 09:55:27 mungady Exp $ 36: * 37: * Changes 38: * ------- 39: * 40: */ 41: 42: package org.jfree.util; 43: 44: import java.io.BufferedOutputStream; 45: import java.io.File; 46: import java.io.FileOutputStream; 47: import java.io.IOException; 48: import java.io.OutputStream; 49: import java.io.OutputStreamWriter; 50: import java.io.Writer; 51: import java.util.ArrayList; 52: import java.util.Collections; 53: import java.util.Iterator; 54: 55: /** 56: * Writes a <code>Configuration</code> instance into a property file, where 57: * the keys are sorted by their name. Writing sorted keys make it easier for 58: * users to find and change properties in the file. 59: * 60: * @author Thomas Morgner 61: */ 62: public class SortedConfigurationWriter { 63: /** 64: * A constant defining that text should be escaped in a way 65: * which is suitable for property keys. 66: */ 67: private static final int ESCAPE_KEY = 0; 68: /** 69: * A constant defining that text should be escaped in a way 70: * which is suitable for property values. 71: */ 72: private static final int ESCAPE_VALUE = 1; 73: /** 74: * A constant defining that text should be escaped in a way 75: * which is suitable for property comments. 76: */ 77: private static final int ESCAPE_COMMENT = 2; 78: 79: /** The system-dependent End-Of-Line separator. */ 80: private static final String END_OF_LINE = StringUtils.getLineSeparator(); 81: 82: /** 83: * The default constructor, does nothing. 84: */ 85: public SortedConfigurationWriter() { 86: } 87: 88: /** 89: * Returns a description for the given key. This implementation returns 90: * null to indicate that no description should be written. Subclasses can 91: * overwrite this method to provide comments for every key. These descriptions 92: * will be included as inline comments. 93: * 94: * @param key the key for which a description should be printed. 95: * @return the description or null if no description should be printed. 96: */ 97: protected String getDescription(final String key) { 98: return null; 99: } 100: 101: /** 102: * Saves the given configuration into a file specified by the given 103: * filename. 104: * 105: * @param filename the filename 106: * @param config the configuration 107: * @throws IOException if an IOError occurs. 108: */ 109: public void save(final String filename, final Configuration config) 110: throws IOException { 111: save(new File(filename), config); 112: } 113: 114: /** 115: * Saves the given configuration into a file specified by the given 116: * file object. 117: * 118: * @param file the target file 119: * @param config the configuration 120: * @throws IOException if an IOError occurs. 121: */ 122: public void save(final File file, final Configuration config) 123: throws IOException { 124: final BufferedOutputStream out = 125: new BufferedOutputStream(new FileOutputStream(file)); 126: save(out, config); 127: out.close(); 128: } 129: 130: 131: /** 132: * Writes the configuration into the given output stream. 133: * 134: * @param outStream the target output stream 135: * @param config the configuration 136: * @throws IOException if writing fails. 137: */ 138: public void save(final OutputStream outStream, final Configuration config) 139: throws IOException { 140: final ArrayList names = new ArrayList(); 141: 142: // clear all previously set configuration settings ... 143: final Iterator defaults = config.findPropertyKeys(""); 144: while (defaults.hasNext()) { 145: final String key = (String) defaults.next(); 146: names.add(key); 147: } 148: 149: Collections.sort(names); 150: 151: final OutputStreamWriter out = 152: new OutputStreamWriter(outStream, "iso-8859-1"); 153: 154: for (int i = 0; i < names.size(); i++) { 155: final String key = (String) names.get(i); 156: final String value = config.getConfigProperty(key); 157: 158: final String description = getDescription(key); 159: if (description != null) { 160: writeDescription(description, out); 161: } 162: saveConvert(key, ESCAPE_KEY, out); 163: out.write("="); 164: saveConvert(value, ESCAPE_VALUE, out); 165: out.write(END_OF_LINE); 166: } 167: out.flush(); 168: 169: } 170: 171: /** 172: * Writes a descriptive comment into the given print writer. 173: * 174: * @param text the text to be written. If it contains more than 175: * one line, every line will be prepended by the comment character. 176: * @param writer the writer that should receive the content. 177: * @throws IOException if writing fails 178: */ 179: private void writeDescription(final String text, final Writer writer) 180: throws IOException { 181: // check if empty content ... this case is easy ... 182: if (text.length() == 0) { 183: return; 184: } 185: 186: writer.write("# "); 187: writer.write(END_OF_LINE); 188: final LineBreakIterator iterator = new LineBreakIterator(text); 189: while (iterator.hasNext()) { 190: writer.write("# "); 191: saveConvert((String) iterator.next(), ESCAPE_COMMENT, writer); 192: writer.write(END_OF_LINE); 193: } 194: } 195: 196: /** 197: * Performs the necessary conversion of an java string into a property 198: * escaped string. 199: * 200: * @param text the text to be escaped 201: * @param escapeMode the mode that should be applied. 202: * @param writer the writer that should receive the content. 203: * @throws IOException if writing fails 204: */ 205: private void saveConvert(final String text, final int escapeMode, 206: final Writer writer) 207: throws IOException { 208: final char[] string = text.toCharArray(); 209: 210: for (int x = 0; x < string.length; x++) { 211: final char aChar = string[x]; 212: switch (aChar) { 213: case ' ': 214: { 215: if ((escapeMode != ESCAPE_COMMENT) 216: && (x == 0 || escapeMode == ESCAPE_KEY)) { 217: writer.write('\\'); 218: } 219: writer.write(' '); 220: break; 221: } 222: case '\\': 223: { 224: writer.write('\\'); 225: writer.write('\\'); 226: break; 227: } 228: case '\t': 229: { 230: if (escapeMode == ESCAPE_COMMENT) { 231: writer.write(aChar); 232: } 233: else { 234: writer.write('\\'); 235: writer.write('t'); 236: } 237: break; 238: } 239: case '\n': 240: { 241: writer.write('\\'); 242: writer.write('n'); 243: break; 244: } 245: case '\r': 246: { 247: writer.write('\\'); 248: writer.write('r'); 249: break; 250: } 251: case '\f': 252: { 253: if (escapeMode == ESCAPE_COMMENT) { 254: writer.write(aChar); 255: } 256: else { 257: writer.write('\\'); 258: writer.write('f'); 259: } 260: break; 261: } 262: case '#': 263: case '"': 264: case '!': 265: case '=': 266: case ':': 267: { 268: if (escapeMode == ESCAPE_COMMENT) { 269: writer.write(aChar); 270: } 271: else { 272: writer.write('\\'); 273: writer.write(aChar); 274: } 275: break; 276: } 277: default: 278: if ((aChar < 0x0020) || (aChar > 0x007e)) { 279: writer.write('\\'); 280: writer.write('u'); 281: writer.write(HEX_CHARS[(aChar >> 12) & 0xF]); 282: writer.write(HEX_CHARS[(aChar >> 8) & 0xF]); 283: writer.write(HEX_CHARS[(aChar >> 4) & 0xF]); 284: writer.write(HEX_CHARS[aChar & 0xF]); 285: } 286: else { 287: writer.write(aChar); 288: } 289: } 290: } 291: } 292: 293: /** A lookup-table. */ 294: private static final char[] HEX_CHARS = 295: {'0', '1', '2', '3', '4', '5', '6', '7', 296: '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 297: }