001: /*
002: * Copyright 2007 Le Duc Bao, Ralf Joachim
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.castor.ddlgen;
017:
018: import java.io.BufferedWriter;
019: import java.io.IOException;
020: import java.io.InterruptedIOException;
021: import java.io.OutputStream;
022: import java.io.OutputStreamWriter;
023: import java.io.Writer;
024: import java.text.MessageFormat;
025:
026: /**
027: * Replace PrintStream and StringBuffer by a Writer implementation
028: * We have various properties to configure output that are in-depended of the schema object:
029: * <li/>org.castor.ddlgen.CharFormat=SENSITIVE, UPPER and LOWER
030: * <li/>org.castor.ddlgen.Newline=\n
031: * <li/>org.castor.ddlgen.Indention=\t
032: *
033: * These properties are accessed at various places all around ddlgen at the moment.The idea
034: * is that these properties are set only once at the new Writer and do not need to be
035: * accessed elsewhere. This has the following advantages:
036: * <li/>improved performance as the properties don't need to be accessed for every object to output
037: * <li/>functionallity to format genertaed ddl is concentrated in one class: the new Writer
038: * <li/>all the toDDL(), toDropDDL(), toCreateDDL() methods get much shorter
039: *
040: * I thought of the following interface for the new Writer (not complete):
041: * <li/>write(String) outputs String as is
042: * <li/>writeln(String) calls write(String) followed by newline()
043: * <li/>newline() output newline and indention of next line
044: * <li/>indent() increases indention
045: * <li/>unindent() decreases indention
046: *
047: * More write() and writeln() methods for other data types may be added on demand. A further
048: * improvement could be to offer write(String, Object[]) methods that internally use
049: * MessageFormat. This would enable us to use a pattern based approach for DDL generation.
050: * These patterns may sometimes be much easier to read and maintain.
051: *
052: * In addition to the introduction of the new Writer it will be required to pass an instance
053: * of the Writer to every method where DDL gets generated. Therefore the parameterless
054: * toCreate() method have to be changed to toCreateDDL(DDLWriter). This also applies to other
055: * such methods.
056: *
057: * @author <a href="mailto:leducbao@gmail.com">Le Duc Bao</a>
058: * @version $Revision: 5951 $ $Date: 2006-04-25 16:09:10 -0600 (Tue, 25 Apr 2006) $
059: * @since 1.1.2
060: */
061: public final class DDLWriter extends Writer {
062: //--------------------------------------------------------------------------
063:
064: /** Print writer to write all output to. */
065: private Writer _writer;
066:
067: /** Remember errors. */
068: private IOException _error = null;
069:
070: /** Newline flag is turn on at a new line before any other character gets written. */
071: private boolean _isNewline = true;
072:
073: /** Current indent level. */
074: private int _indentLevel = 0;
075:
076: /** String to output to indent a line. */
077: private String _indentText = DDLGenConfiguration.DEFAULT_INDENT;
078:
079: /** String to output for a new line. */
080: private String _newline = DDLGenConfiguration.DEFAULT_NEWLINE;
081:
082: /** Character format defined by CHAR_FORMAT_KEY in configuration file. */
083: private String _chrFormat = DDLGenConfiguration.CHAR_FORMAT_SENSITIVE;
084:
085: //--------------------------------------------------------------------------
086:
087: /**
088: * Construct new DDLWriter with given output stream and configuration file.
089: *
090: * @param output Output stream to write output characters to.
091: * @param conf Configuration.
092: */
093: public DDLWriter(final OutputStream output, final Configuration conf) {
094: this (new BufferedWriter(new OutputStreamWriter(output)), conf);
095: }
096:
097: /**
098: * Construct new DDLWriter with given writer and configuration file.
099: *
100: * @param writer Writer to write output characters to.
101: * @param conf Configuration.
102: */
103: public DDLWriter(final Writer writer, final Configuration conf) {
104: super (writer);
105:
106: _writer = writer;
107:
108: _newline = conf.getStringValue(DDLGenConfiguration.NEWLINE_KEY,
109: DDLGenConfiguration.DEFAULT_NEWLINE);
110: _indentText = conf.getStringValue(
111: DDLGenConfiguration.INDENT_KEY,
112: DDLGenConfiguration.DEFAULT_INDENT);
113: _chrFormat = conf.getStringValue(
114: DDLGenConfiguration.CHAR_FORMAT_KEY,
115: DDLGenConfiguration.CHAR_FORMAT_SENSITIVE);
116: }
117:
118: /**
119: * Flush the writer.
120: */
121: public void flush() {
122: try {
123: synchronized (lock) {
124: if (_writer == null) {
125: throw new IOException("Writer closed.");
126: }
127: _writer.flush();
128: }
129: } catch (IOException ex) {
130: _error = ex;
131: }
132: }
133:
134: /**
135: * Close the writer.
136: */
137: public void close() {
138: try {
139: synchronized (lock) {
140: if (_writer != null) {
141: _writer.close();
142: _writer = null;
143: }
144: }
145: } catch (IOException ex) {
146: _error = ex;
147: }
148: }
149:
150: /**
151: * Check if any error occured at previous operations of the writer. If an IOException was
152: * caught at any previous operation of the writer it will be thrown now.
153: *
154: * @throws IOException IOException caught at any previous operation of the writer.
155: */
156: public void checkError() throws IOException {
157: if (_error != null) {
158: throw _error;
159: }
160: }
161:
162: //--------------------------------------------------------------------------
163:
164: /**
165: * Increase indention by 1.
166: */
167: public void indent() {
168: _indentLevel++;
169: }
170:
171: /**
172: * Decrease indention by 1.
173: */
174: public void unindent() {
175: _indentLevel = (_indentLevel <= 0) ? 0 : _indentLevel - 1;
176: }
177:
178: //--------------------------------------------------------------------------
179:
180: /**
181: * {@inheritDoc}
182: */
183: public void write(final char[] buf, final int off, final int len) {
184: write(new String(buf, off, len));
185: }
186:
187: /**
188: * {@inheritDoc}
189: */
190: public void write(final char[] buf) {
191: write(new String(buf));
192: }
193:
194: /**
195: * {@inheritDoc}
196: */
197: public void write(final int c) {
198: write(new String(new char[] { (char) c }));
199: }
200:
201: /**
202: * {@inheritDoc}
203: */
204: public void write(final String s, final int off, final int len) {
205: write(s.substring(off, off + len));
206: }
207:
208: /**
209: * {@inheritDoc}
210: */
211: public void write(final String s) {
212: if (s != null) {
213: try {
214: synchronized (lock) {
215: if (_writer == null) {
216: throw new IOException("Writer closed.");
217: }
218:
219: if (DDLGenConfiguration.CHAR_FORMAT_LOWER
220: .equalsIgnoreCase(_chrFormat)) {
221: _writer.write(s.toLowerCase());
222: } else if (DDLGenConfiguration.CHAR_FORMAT_UPPER
223: .equalsIgnoreCase(_chrFormat)) {
224: _writer.write(s.toUpperCase());
225: } else {
226: _writer.write(s);
227: }
228: }
229: } catch (InterruptedIOException ex) {
230: Thread.currentThread().interrupt();
231: } catch (IOException ex) {
232: _error = ex;
233: }
234: }
235: }
236:
237: /**
238: * Write indention.
239: */
240: private void writeIndention() {
241: try {
242: synchronized (lock) {
243: if (_writer == null) {
244: throw new IOException("Writer closed.");
245: }
246:
247: if (_isNewline) {
248: for (int i = 0; i < _indentLevel; i++) {
249: _writer.write(_indentText);
250: }
251:
252: _isNewline = false;
253: }
254: }
255: } catch (InterruptedIOException ex) {
256: Thread.currentThread().interrupt();
257: } catch (IOException ex) {
258: _error = ex;
259: }
260: }
261:
262: /**
263: * Write newline.
264: */
265: private void writeNewline() {
266: try {
267: synchronized (lock) {
268: if (_writer == null) {
269: throw new IOException("Writer closed.");
270: }
271:
272: _isNewline = true;
273:
274: _writer.write(_newline);
275: }
276: } catch (InterruptedIOException ex) {
277: Thread.currentThread().interrupt();
278: } catch (IOException ex) {
279: _error = ex;
280: }
281: }
282:
283: //--------------------------------------------------------------------------
284:
285: /**
286: * Print an array of characters.
287: *
288: * @param chars Array of chars to be printed.
289: */
290: public void print(final char[] chars) {
291: synchronized (lock) {
292: writeIndention();
293: write(chars);
294: }
295: }
296:
297: /**
298: * Print a double-precision floating-point number.
299: *
300: * @param number Double to be printed.
301: */
302: public void print(final double number) {
303: synchronized (lock) {
304: writeIndention();
305: write(String.valueOf(number));
306: }
307: }
308:
309: /**
310: * Print an integer number.
311: *
312: * @param number Integer to be printed.
313: */
314: public void print(final int number) {
315: synchronized (lock) {
316: writeIndention();
317: write(String.valueOf(number));
318: }
319: }
320:
321: /**
322: * Print a long number.
323: *
324: * @param number Long to be printed.
325: */
326: public void print(final long number) {
327: synchronized (lock) {
328: writeIndention();
329: write(String.valueOf(number));
330: }
331: }
332:
333: /**
334: * Print an object.
335: *
336: * @param object Object to be printed.
337: */
338: public void print(final Object object) {
339: synchronized (lock) {
340: writeIndention();
341: write(String.valueOf(object));
342: }
343: }
344:
345: /**
346: * Print a string.
347: *
348: * @param string String to be printed.
349: */
350: public void print(final String string) {
351: synchronized (lock) {
352: writeIndention();
353: write(string);
354: }
355: }
356:
357: /**
358: * A convenience method to print a formatted string build by filling placeholders of the
359: * specified pattern with given arguments.
360: *
361: * @param pattern Pattern with placeholders.
362: * @param arguments Arguments to replace placeholders in pattern.
363: */
364: public void print(final String pattern, final Object[] arguments) {
365: synchronized (lock) {
366: writeIndention();
367: write(MessageFormat.format(pattern, arguments));
368: }
369: }
370:
371: //--------------------------------------------------------------------------
372:
373: /**
374: * Terminate the current line by writing the line separator string.
375: */
376: public void println() {
377: writeNewline();
378: }
379:
380: /**
381: * Print an array of characters and terminate the line.
382: *
383: * @param chars Array of chars to be printed.
384: */
385: public void println(final char[] chars) {
386: synchronized (lock) {
387: writeIndention();
388: write(chars);
389: writeNewline();
390: }
391: }
392:
393: /**
394: * Print a double-precision floating-point number and terminate the line.
395: *
396: * @param number Double to be printed.
397: */
398: public void println(final double number) {
399: synchronized (lock) {
400: writeIndention();
401: write(String.valueOf(number));
402: writeNewline();
403: }
404: }
405:
406: /**
407: * Print an integer number and terminate the line.
408: *
409: * @param number Integer to be printed.
410: */
411: public void println(final int number) {
412: synchronized (lock) {
413: writeIndention();
414: write(String.valueOf(number));
415: writeNewline();
416: }
417: }
418:
419: /**
420: * Print a long number and terminate the line.
421: *
422: * @param number Long to be printed.
423: */
424: public void println(final long number) {
425: synchronized (lock) {
426: writeIndention();
427: write(String.valueOf(number));
428: writeNewline();
429: }
430: }
431:
432: /**
433: * Print an object and terminate the line.
434: *
435: * @param object Object to be printed.
436: */
437: public void println(final Object object) {
438: synchronized (lock) {
439: writeIndention();
440: write(String.valueOf(object));
441: writeNewline();
442: }
443: }
444:
445: /**
446: * Print a string and terminate the line.
447: *
448: * @param string String to be printed.
449: */
450: public void println(final String string) {
451: synchronized (lock) {
452: writeIndention();
453: write(string);
454: writeNewline();
455: }
456: }
457:
458: /**
459: * A convenience method to print a formatted string build by filling placeholders of the
460: * specified pattern with given arguments. Line will be terminated after the formatted string.
461: *
462: * @param pattern Pattern with placeholders.
463: * @param arguments Arguments to replace placeholders in pattern.
464: */
465: public void println(final String pattern, final Object[] arguments) {
466: synchronized (lock) {
467: writeIndention();
468: write(MessageFormat.format(pattern, arguments));
469: writeNewline();
470: }
471: }
472:
473: //--------------------------------------------------------------------------
474: }
|