/*
* 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();
}
}
//--------------------------------------------------------------------------
}