001: /*
002:
003: Derby - Class org.apache.derby.impl.load.ExportWriteData
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.load;
023:
024: import java.io.FileOutputStream;
025: import java.io.BufferedOutputStream;
026: import java.io.OutputStreamWriter;
027: import java.net.MalformedURLException;
028: import java.net.URL;
029: import java.util.Date;
030: import java.io.IOException;
031:
032: //this class takes the passed row and writes it into the data file using the
033: //properties from the control file
034: //FIXED FORMAT: if length of nullstring is greater than column width, throw execption
035:
036: final class ExportWriteData extends ExportWriteDataAbstract implements
037: java.security.PrivilegedExceptionAction {
038:
039: private String outputFileName;
040: // i18n support - instead of using DataOutputStream.writeBytes - use
041: // OutputStreamWriter.write with the correct codeset.
042: private OutputStreamWriter aStream;
043:
044: //writes data into the o/p file using control file properties
045: ExportWriteData(String outputFileName, ControlInfo controlFileReader)
046: throws Exception {
047: this .outputFileName = outputFileName;
048: this .controlFileReader = controlFileReader;
049: loadPropertiesInfo();
050:
051: try {
052: java.security.AccessController.doPrivileged(this );
053: } catch (java.security.PrivilegedActionException pae) {
054: throw pae.getException();
055: }
056:
057: }
058:
059: public final Object run() throws Exception {
060: openFile();
061: return null;
062: }
063:
064: //prepares the o/p file for writing
065: private void openFile() throws Exception {
066: try {
067: URL url = new URL(outputFileName);
068: outputFileName = url.getFile();
069: } catch (MalformedURLException ex) {
070: }
071: FileOutputStream anOutputStream = new FileOutputStream(
072: outputFileName);
073: BufferedOutputStream buffered = new BufferedOutputStream(
074: anOutputStream);
075:
076: aStream = dataCodeset == null ? new OutputStreamWriter(buffered)
077: : new OutputStreamWriter(buffered, dataCodeset);
078: }
079:
080: /**if control file says true for column definition, write it as first line of the
081: * data file
082: * @exception Exception if there is an error
083: */
084: void writeColumnDefinitionOptionally(String[] columnNames,
085: String[] columnTypes) throws Exception {
086: boolean ignoreColumnTypes = true;
087:
088: //do uppercase because the ui shows the values as True and False
089: if (columnDefinition.toUpperCase(java.util.Locale.ENGLISH)
090: .equals(
091: ControlInfo.INTERNAL_TRUE
092: .toUpperCase(java.util.Locale.ENGLISH))) {
093: String tempStr = new String();
094: //put the start and stop delimiters around the column name and type
095: for (int i = 0; i < columnNames.length; i++) {
096: // take care at adding fieldSeparator at the
097: // end of the field if needed
098: if (i > 0) {
099: tempStr = fieldSeparator;
100: } else {
101: tempStr = "";
102: }
103:
104: tempStr = tempStr + fieldStartDelimiter
105: + columnNames[i] + fieldStopDelimiter;
106: if (ignoreColumnTypes == false) {
107: tempStr = tempStr + fieldSeparator
108: + fieldStartDelimiter + columnTypes[i]
109: + fieldStopDelimiter;
110: }
111:
112: aStream.write(tempStr, 0, tempStr.length());
113: }
114: aStream.write(recordSeparator, 0, recordSeparator.length());
115: }
116: }
117:
118: //puts the start and stop delimiters only if column value contains field/record separator
119: //in it
120: private void writeNextColumn(String oneColumn, boolean isNumeric)
121: throws Exception {
122: if (oneColumn != null) {
123: //put the start and end delimiters always
124: //because of the bug 2045, I broke down following
125: //aStream.writeBytes(fieldStartDelimiter+oneColumn+fieldStopDelimiter);
126: //into 3 writeBytes. That bug had a table with long bit varying datatype and while
127: //writing data from that column using the stream, it would run out of memory.
128: // i18n - write using the write method of OutputStreamWriter
129: if (!isNumeric)
130: aStream.write(fieldStartDelimiter, 0,
131: fieldStartDelimiter.length());
132: //convert the string to double character delimiters format if requred.
133: if (doubleDelimiter)
134: oneColumn = makeDoubleDelimiterString(oneColumn,
135: fieldStartDelimiter);
136: aStream.write(oneColumn, 0, oneColumn.length());
137: if (!isNumeric)
138: aStream.write(fieldStopDelimiter, 0, fieldStopDelimiter
139: .length());
140: }
141: }
142:
143: /**write the passed row into the data file
144: * @exception Exception if there is an error
145: */
146: public void writeData(String[] oneRow, boolean[] isNumeric)
147: throws Exception {
148: if (format.equals(ControlInfo.DEFAULT_FORMAT)) {
149: //if format is delimited, write column data and field separator and then the record separator
150: //if a column's value is null, write just the column separator
151: writeNextColumn(oneRow[0], isNumeric[0]);
152: for (int i = 1; i < oneRow.length; i++) {
153: aStream.write(fieldSeparator, 0, fieldSeparator
154: .length());
155: writeNextColumn(oneRow[i], isNumeric[i]);
156: }
157: if (hasDelimiterAtEnd) { //write an additional delimeter if user wants one at the end of each row
158: aStream.write(fieldSeparator, 0, fieldSeparator
159: .length());
160: }
161: }
162: aStream.write(recordSeparator, 0, recordSeparator.length());
163: }
164:
165: /**if nothing more to write, then close the file and write a message of completion
166: * in message file
167: *@exception Exception if there is an error
168: */
169: public void noMoreRows() throws IOException {
170: aStream.flush();
171: aStream.close();
172: // System.err.print(new Date(System.currentTimeMillis()) + " ");
173: // System.err.println("Export finished");
174: // System.setErr(System.out);
175: }
176:
177: /*
178: * Convert the input string into double delimiter format for export.
179: * double character delimiter recognition in delimited format
180: * files applies to the export and import utilities. Character delimiters are
181: * permitted within the character-based fields of a file. This applies to
182: * fields of type CHAR, VARCHAR, LONGVARCHAR, or CLOB. Any pair of character
183: * delimiters found between the enclosing character delimiters is imported
184: * into the database. For example with doble quote(") as character delimiter
185: *
186: * "What a ""nice""day!"
187: *
188: * will be imported as:
189: *
190: * What a "nice"day!
191: *
192: * In the case of export, the rule applies in reverse. For example,
193: *
194: * I am 6"tall.
195: *
196: * will be exported to a file as:
197: *
198: * "I am 6""tall."
199:
200: */
201: private String makeDoubleDelimiterString(String inputString,
202: String charDelimiter) {
203: int start = inputString.indexOf(charDelimiter);
204: StringBuffer result;
205: //if delimeter is not found inside the string nothing to do
206: if (start != -1) {
207: result = new StringBuffer(inputString);
208: int current;
209: int delLength = charDelimiter.length();
210: while (start != -1) {
211: //insert delimter character
212: result = result.insert(start, charDelimiter);
213: current = start + delLength + 1;
214: start = result.toString().indexOf(charDelimiter,
215: current);
216: }
217: return result.toString();
218: }
219: return inputString;
220: }
221: }
|