/* * Copyright 2007 Le Duc Bao, Ralf Joachim * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.castor.ddlgen; import java.io.BufferedWriter; import java.io.IOException; import java.io.InterruptedIOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.text.MessageFormat; /** * Replace PrintStream and StringBuffer by a Writer implementation * We have various properties to configure output that are in-depended of the schema object: * <li/>org.castor.ddlgen.CharFormat=SENSITIVE, UPPER and LOWER * <li/>org.castor.ddlgen.Newline=\n * <li/>org.castor.ddlgen.Indention=\t * * These properties are accessed at various places all around ddlgen at the moment.The idea * is that these properties are set only once at the new Writer and do not need to be * accessed elsewhere. This has the following advantages: * <li/>improved performance as the properties don't need to be accessed for every object to output * <li/>functionallity to format genertaed ddl is concentrated in one class: the new Writer * <li/>all the toDDL(), toDropDDL(), toCreateDDL() methods get much shorter * * I thought of the following interface for the new Writer (not complete): * <li/>write(String) outputs String as is * <li/>writeln(String) calls write(String) followed by newline() * <li/>newline() output newline and indention of next line * <li/>indent() increases indention * <li/>unindent() decreases indention * * More write() and writeln() methods for other data types may be added on demand. A further * improvement could be to offer write(String, Object[]) methods that internally use * MessageFormat. This would enable us to use a pattern based approach for DDL generation. * These patterns may sometimes be much easier to read and maintain. * * In addition to the introduction of the new Writer it will be required to pass an instance * of the Writer to every method where DDL gets generated. Therefore the parameterless * toCreate() method have to be changed to toCreateDDL(DDLWriter). This also applies to other * such methods. * * @author <a href="mailto:leducbao@gmail.com">Le Duc Bao</a> * @version $Revision: 5951 $ $Date: 2006-04-25 16:09:10 -0600 (Tue, 25 Apr 2006) $ * @since 1.1.2 */ public final class DDLWriter extends Writer { //-------------------------------------------------------------------------- /** Print writer to write all output to. */ private Writer _writer; /** Remember errors. */ private IOException _error = null; /** Newline flag is turn on at a new line before any other character gets written. */ private boolean _isNewline = true; /** Current indent level. */ private int _indentLevel = 0; /** String to output to indent a line. */ private String _indentText = DDLGenConfiguration.DEFAULT_INDENT; /** String to output for a new line. */ private String _newline = DDLGenConfiguration.DEFAULT_NEWLINE; /** Character format defined by CHAR_FORMAT_KEY in configuration file. */ private String _chrFormat = DDLGenConfiguration.CHAR_FORMAT_SENSITIVE; //-------------------------------------------------------------------------- /** * Construct new DDLWriter with given output stream and configuration file. * * @param output Output stream to write output characters to. * @param conf Configuration. */ public DDLWriter(final OutputStream output, final Configuration conf) { this(new BufferedWriter(new OutputStreamWriter(output)), conf); } /** * Construct new DDLWriter with given writer and configuration file. * * @param writer Writer to write output characters to. * @param conf Configuration. */ public DDLWriter(final Writer writer, final Configuration conf) { super(writer); _writer = writer; _newline = conf.getStringValue( DDLGenConfiguration.NEWLINE_KEY, DDLGenConfiguration.DEFAULT_NEWLINE); _indentText = conf.getStringValue( DDLGenConfiguration.INDENT_KEY, DDLGenConfiguration.DEFAULT_INDENT); _chrFormat = conf.getStringValue( DDLGenConfiguration.CHAR_FORMAT_KEY, DDLGenConfiguration.CHAR_FORMAT_SENSITIVE); } /** * Flush the writer. */ public void flush() { try { synchronized (lock) { if (_writer == null) { throw new IOException("Writer closed."); } _writer.flush(); } } catch (IOException ex) { _error = ex; } } /** * Close the writer. */ public void close () { try { synchronized (lock) { if (_writer != null) { _writer.close(); _writer = null; } } } catch (IOException ex) { _error = ex; } } /** * Check if any error occured at previous operations of the writer. If an IOException was * caught at any previous operation of the writer it will be thrown now. * * @throws IOException IOException caught at any previous operation of the writer. */ public void checkError() throws IOException { if (_error != null) { throw _error; } } //-------------------------------------------------------------------------- /** * Increase indention by 1. */ public void indent() { _indentLevel++; } /** * Decrease indention by 1. */ public void unindent() { _indentLevel = (_indentLevel <= 0) ? 0 : _indentLevel - 1; } //-------------------------------------------------------------------------- /** * {@inheritDoc} */ public void write(final char[] buf, final int off, final int len) { write(new String(buf, off, len)); } /** * {@inheritDoc} */ public void write(final char[] buf) { write(new String(buf)); } /** * {@inheritDoc} */ public void write(final int c) { write(new String(new char[] {(char) c})); } /** * {@inheritDoc} */ public void write(final String s, final int off, final int len) { write(s.substring(off, off + len)); } /** * {@inheritDoc} */ public void write(final String s) { if (s != null) { try { synchronized (lock) { if (_writer == null) { throw new IOException("Writer closed."); } if (DDLGenConfiguration.CHAR_FORMAT_LOWER.equalsIgnoreCase(_chrFormat)) { _writer.write(s.toLowerCase()); } else if (DDLGenConfiguration.CHAR_FORMAT_UPPER.equalsIgnoreCase(_chrFormat)) { _writer.write(s.toUpperCase()); } else { _writer.write(s); } } } catch (InterruptedIOException ex) { Thread.currentThread().interrupt(); } catch (IOException ex) { _error = ex; } } } /** * Write indention. */ private void writeIndention() { try { synchronized (lock) { if (_writer == null) { throw new IOException("Writer closed."); } if (_isNewline) { for (int i = 0; i < _indentLevel; i++) { _writer.write(_indentText); } _isNewline = false; } } } catch (InterruptedIOException ex) { Thread.currentThread().interrupt(); } catch (IOException ex) { _error = ex; } } /** * Write newline. */ private void writeNewline() { try { synchronized (lock) { if (_writer == null) { throw new IOException("Writer closed."); } _isNewline = true; _writer.write(_newline); } } catch (InterruptedIOException ex) { Thread.currentThread().interrupt(); } catch (IOException ex) { _error = ex; } } //-------------------------------------------------------------------------- /** * Print an array of characters. * * @param chars Array of chars to be printed. */ public void print(final char[] chars) { synchronized (lock) { writeIndention(); write(chars); } } /** * Print a double-precision floating-point number. * * @param number Double to be printed. */ public void print(final double number) { synchronized (lock) { writeIndention(); write(String.valueOf(number)); } } /** * Print an integer number. * * @param number Integer to be printed. */ public void print(final int number) { synchronized (lock) { writeIndention(); write(String.valueOf(number)); } } /** * Print a long number. * * @param number Long to be printed. */ public void print(final long number) { synchronized (lock) { writeIndention(); write(String.valueOf(number)); } } /** * Print an object. * * @param object Object to be printed. */ public void print(final Object object) { synchronized (lock) { writeIndention(); write(String.valueOf(object)); } } /** * Print a string. * * @param string String to be printed. */ public void print(final String string) { synchronized (lock) { writeIndention(); write(string); } } /** * A convenience method to print a formatted string build by filling placeholders of the * specified pattern with given arguments. * * @param pattern Pattern with placeholders. * @param arguments Arguments to replace placeholders in pattern. */ public void print(final String pattern, final Object[] arguments) { synchronized (lock) { writeIndention(); write(MessageFormat.format(pattern, arguments)); } } //-------------------------------------------------------------------------- /** * Terminate the current line by writing the line separator string. */ public void println() { writeNewline(); } /** * Print an array of characters and terminate the line. * * @param chars Array of chars to be printed. */ public void println(final char[] chars) { synchronized (lock) { writeIndention(); write(chars); writeNewline(); } } /** * Print a double-precision floating-point number and terminate the line. * * @param number Double to be printed. */ public void println(final double number) { synchronized (lock) { writeIndention(); write(String.valueOf(number)); writeNewline(); } } /** * Print an integer number and terminate the line. * * @param number Integer to be printed. */ public void println(final int number) { synchronized (lock) { writeIndention(); write(String.valueOf(number)); writeNewline(); } } /** * Print a long number and terminate the line. * * @param number Long to be printed. */ public void println(final long number) { synchronized (lock) { writeIndention(); write(String.valueOf(number)); writeNewline(); } } /** * Print an object and terminate the line. * * @param object Object to be printed. */ public void println(final Object object) { synchronized (lock) { writeIndention(); write(String.valueOf(object)); writeNewline(); } } /** * Print a string and terminate the line. * * @param string String to be printed. */ public void println(final String string) { synchronized (lock) { writeIndention(); write(string); writeNewline(); } } /** * A convenience method to print a formatted string build by filling placeholders of the * specified pattern with given arguments. Line will be terminated after the formatted string. * * @param pattern Pattern with placeholders. * @param arguments Arguments to replace placeholders in pattern. */ public void println(final String pattern, final Object[] arguments) { synchronized (lock) { writeIndention(); write(MessageFormat.format(pattern, arguments)); writeNewline(); } } //-------------------------------------------------------------------------- }