Source for org.jfree.util.SortedConfigurationWriter

   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: }