001: /*
002: * (c) Copyright 2007 by Volker Bergmann. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, is permitted under the terms of the
006: * GNU General Public License.
007: *
008: * For redistributing this software or a derivative work under a license other
009: * than the GPL-compatible Free Software License as defined by the Free
010: * Software Foundation or approved by OSI, you must first obtain a commercial
011: * license to this software product from Volker Bergmann.
012: *
013: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
014: * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
015: * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
016: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
017: * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
018: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
019: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
020: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
021: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
022: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
023: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
024: * POSSIBILITY OF SUCH DAMAGE.
025: */
026:
027: package org.databene.platform.flat;
028:
029: import org.databene.model.consumer.AbstractConsumer;
030: import org.databene.model.data.Entity;
031: import org.databene.model.data.ComponentAccessor;
032: import org.databene.document.flat.FlatFileColumnDescriptor;
033: import org.databene.commons.*;
034: import org.databene.commons.converter.AccessingConverter;
035: import org.databene.commons.converter.ConverterChain;
036: import org.databene.commons.converter.FormatFormatConverter;
037: import org.databene.commons.format.Alignment;
038: import org.databene.commons.format.PadFormat;
039: import org.apache.commons.logging.Log;
040: import org.apache.commons.logging.LogFactory;
041:
042: import java.io.FileWriter;
043: import java.io.IOException;
044: import java.io.PrintWriter;
045: import java.text.ParsePosition;
046: import java.text.ParseException;
047:
048: /**
049: * Exports Entities to flat files.<br/>
050: * <br/>
051: * Created: 26.08.2007 06:17:41
052: * @author Volker Bergmann
053: */
054: public class FlatFileEntityExporter extends AbstractConsumer<Entity> {
055:
056: private static final Log logger = LogFactory
057: .getLog(FlatFileEntityExporter.class);
058:
059: private String uri;
060: private Converter<Entity, String> converters[];
061:
062: private PrintWriter printer;
063:
064: public FlatFileEntityExporter() {
065: this (null, null);
066: }
067:
068: public FlatFileEntityExporter(String uri, String propertyFormatList) {
069: super ();
070: this .uri = uri;
071: setProperties(propertyFormatList);
072: }
073:
074: // properties ------------------------------------------------------------------------------------------------------
075:
076: public void setUri(String uri) {
077: this .uri = uri;
078: }
079:
080: public void setProperties(String propertyFormatList) { // TODO v0.5 simplify by FlatFileUtil
081: if (propertyFormatList == null) {
082: converters = null;
083: return;
084: }
085: try {
086: String[] propertyFormats = StringUtil.tokenize(
087: propertyFormatList, ',');
088: this .converters = new Converter[propertyFormats.length];
089: for (int i = 0; i < propertyFormats.length; i++) {
090: String propertyFormat = propertyFormats[i];
091: int lbIndex = propertyFormat.indexOf('[');
092: if (lbIndex < 0)
093: throw new ConfigurationError(
094: "'[' expected in property format descriptor '"
095: + propertyFormat + "'");
096: int rbIndex = propertyFormat.indexOf(']');
097: if (rbIndex < 0)
098: throw new ConfigurationError(
099: "']' expected in property format descriptor '"
100: + propertyFormat + "'");
101: String propertyName = propertyFormat.substring(0,
102: lbIndex);
103: // parse width
104: ParsePosition pos = new ParsePosition(lbIndex + 1);
105: int width = (int) ParseUtil.parseNonNegativeInteger(
106: propertyFormat, pos);
107: // parse fractionDigits
108: int minFractionDigits = 0;
109: int maxFractionDigits = 2;
110: if (pos.getIndex() < rbIndex
111: && propertyFormat.charAt(pos.getIndex()) == '.') {
112: pos.setIndex(pos.getIndex() + 1);
113: minFractionDigits = (int) ParseUtil
114: .parseNonNegativeInteger(propertyFormat,
115: pos);
116: maxFractionDigits = minFractionDigits;
117: }
118: // parse alignment
119: Alignment alignment = Alignment.LEFT;
120: if (pos.getIndex() < rbIndex) {
121: char alignmentCode = propertyFormat.charAt(pos
122: .getIndex());
123: switch (alignmentCode) {
124: case 'l':
125: alignment = Alignment.LEFT;
126: break;
127: case 'r':
128: alignment = Alignment.RIGHT;
129: break;
130: case 'c':
131: alignment = Alignment.CENTER;
132: break;
133: default:
134: throw new ConfigurationError(
135: "Illegal alignment code '"
136: + alignmentCode
137: + "' in property format descriptor '"
138: + propertyFormat + "'");
139: }
140: pos.setIndex(pos.getIndex() + 1);
141: }
142: // parse pad char
143: char padChar = ' ';
144: if (pos.getIndex() < rbIndex)
145: padChar = propertyFormat.charAt(pos.getIndex());
146: assert pos.getIndex() == rbIndex;
147: FlatFileColumnDescriptor descriptor = new FlatFileColumnDescriptor(
148: propertyName, width, alignment, padChar);
149: this .converters[i] = new ConverterChain<Entity, String>(
150: new AccessingConverter<Entity, Object>(
151: Object.class, new ComponentAccessor(
152: descriptor.getName())),
153: new FormatFormatConverter(new PadFormat(
154: descriptor.getWidth(),
155: minFractionDigits, maxFractionDigits,
156: descriptor.getAlignment(), padChar)));
157: }
158: } catch (ParseException e) {
159: throw new ConfigurationError("Invalid format: "
160: + propertyFormatList, e);
161: }
162: }
163:
164: // Consumer interface ----------------------------------------------------------------------------------------------
165:
166: public void startConsuming(Entity entity) {
167: try {
168: if (printer == null) {
169: // it's the first call, we need to create the PrintWriter
170: if (this .uri == null)
171: throw new ConfigurationError(
172: "Property 'uri' not set on bean "
173: + getClass().getName());
174: if (this .converters == null)
175: throw new ConfigurationError(
176: "Property 'properties' not set on bean "
177: + getClass().getName());
178: printer = new PrintWriter(new FileWriter(uri));
179: }
180: if (logger.isDebugEnabled())
181: logger.debug("exporting " + entity);
182: for (Converter<Entity, String> converter : converters) {
183: printer.print(converter.convert(entity));
184: }
185: printer.println();
186: } catch (IOException e) {
187: throw new RuntimeException(e);
188: }
189: }
190:
191: public void flush() {
192: if (printer != null)
193: printer.flush();
194: }
195:
196: public void close() {
197: IOUtil.close(printer);
198: }
199:
200: // java.lang.Object overrrides -------------------------------------------------------------------------------------
201:
202: public String toString() {
203: return getClass().getSimpleName() + '[' + ArrayFormat.format()
204: + ']';
205: }
206: }
|