001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.mashup.db.bootstrap;
042:
043: import java.io.BufferedReader;
044: import java.io.File;
045: import java.io.FileInputStream;
046: import java.io.FileReader;
047: import java.io.IOException;
048: import java.io.InputStream;
049: import java.io.InputStreamReader;
050: import java.net.URL;
051: import java.sql.Types;
052: import java.util.ArrayList;
053: import java.util.Collections;
054: import java.util.List;
055:
056: import org.netbeans.modules.mashup.db.common.FlatfileDBException;
057: import org.netbeans.modules.mashup.db.common.PropertyKeys;
058: import org.netbeans.modules.mashup.db.common.SQLUtils;
059: import org.netbeans.modules.mashup.db.model.FlatfileDBColumn;
060: import org.netbeans.modules.mashup.db.model.FlatfileDBTable;
061: import org.netbeans.modules.mashup.db.model.impl.FlatfileDBColumnImpl;
062:
063: import com.sun.sql.framework.utils.StringUtil;
064:
065: /**
066: * Extends base class to provide fixed-width file implementation of
067: * FlatfileBootstrapParser.
068: *
069: * @author Ahimanikya Satapathy
070: * @version $Revision$
071: */
072: public class FixedWidthBootstrapParser implements
073: FlatfileBootstrapParser {
074:
075: /** Creates a new default instance of FixedWidthBootstrapParser. */
076: public FixedWidthBootstrapParser() {
077: }
078:
079: public boolean acceptable(FlatfileDBTable table)
080: throws FlatfileDBException {
081: File dataFile = new File(table.getLocalFilePath(), table
082: .getFileName());
083: BufferedReader reader = null;
084: boolean fixedWidth = false;
085:
086: try {
087: reader = new BufferedReader(new FileReader(dataFile));
088: int lastRecLength = 0;
089: int recLength = 0;
090: for (int count = 0; count < 5; count++) {
091: String line = reader.readLine();
092: if (line == null) {
093: break;
094: }
095:
096: recLength = line.length();
097: if (lastRecLength == 0) {
098: lastRecLength = recLength;
099: recLength = 0;
100: } else if (lastRecLength == recLength) {
101: fixedWidth = true;
102: lastRecLength = recLength;
103: recLength = 0;
104: } else {
105: fixedWidth = false;
106: break;
107: }
108: }
109: } catch (Exception e) {
110: throw new FlatfileDBException("Unable to parse data file: ");
111: } finally {
112: if (reader != null) {
113: try {
114: reader.close();
115: } catch (IOException e) {
116: // ignore
117: }
118: }
119: }
120: return fixedWidth;
121: }
122:
123: /**
124: * @see org.netbeans.modules.mashup.db.bootstrap.FlatfileBootstrapParser#getFlatfileFields
125: */
126: public List buildFlatfileDBColumns(FlatfileDBTable table)
127: throws FlatfileDBException {
128: if (table == null || table.getProperties() == null
129: || table.getProperties().size() == 0) {
130: return Collections.EMPTY_LIST;
131: }
132:
133: int recordLength = 0;
134: int fieldCount = 0;
135: int offset = 0;
136:
137: int jdbcType = SQLUtils.getStdJdbcType(table
138: .getProperty(PropertyKeys.WIZARDDEFAULTSQLTYPE));
139: if (jdbcType == SQLUtils.JDBCSQL_TYPE_UNDEFINED) {
140: jdbcType = Types.VARCHAR;
141: }
142:
143: try {
144: recordLength = Integer.valueOf(
145: table.getProperty(PropertyKeys.WIZARDRECORDLENGTH))
146: .intValue();
147: fieldCount = Integer.valueOf(
148: table.getProperty(PropertyKeys.WIZARDFIELDCOUNT))
149: .intValue();
150: } catch (Exception e) {
151: return Collections.EMPTY_LIST;
152: }
153:
154: try {
155: offset = Integer.valueOf(
156: table.getProperty(PropertyKeys.HEADERBYTESOFFSET))
157: .intValue();
158: } catch (Exception e) {
159: offset = 0;
160: }
161:
162: boolean isFirstLineHeader = Boolean.valueOf(
163: table.getProperty(PropertyKeys.ISFIRSTLINEHEADER))
164: .booleanValue();
165:
166: try {
167: if (!isFirstLineHeader) {
168: final int basicLength = recordLength / fieldCount;
169: int remainderLength = basicLength;
170: assertRecordLength(recordLength, fieldCount);
171:
172: // Append remainder, if any, to last field.
173: if ((recordLength - (basicLength % fieldCount)) != 0) {
174: remainderLength += recordLength % fieldCount;
175: }
176:
177: return generateColumnNames(table, fieldCount, jdbcType,
178: basicLength, remainderLength);
179: } else {
180: return readHeaderFromFirstLine(table, offset, jdbcType,
181: recordLength);
182: }
183: } catch (ArithmeticException ae) {
184: throw new FlatfileDBException(getErrMessage(fieldCount));
185: }
186: }
187:
188: public void makeGuess(FlatfileDBTable table)
189: throws FlatfileDBException {
190: File dataFile = new File(table.getLocalFilePath(), table
191: .getFileName());
192: int recLength = 0;
193: BufferedReader reader = null;
194:
195: try {
196: reader = new BufferedReader(new FileReader(dataFile));
197: String line = reader.readLine();
198: if (line != null) {
199: recLength = line.length();
200: }
201: } catch (Exception e) {
202: throw new FlatfileDBException("Unable to parse data file: ");
203: } finally {
204: if (reader != null) {
205: try {
206: reader.close();
207: } catch (IOException e) {
208: // ignore
209: }
210: }
211: }
212:
213: if (recLength > 1) {
214: List colList = readHeaderFromFirstLine(table, 0,
215: Types.VARCHAR, recLength);
216:
217: table.setProperty(PropertyKeys.WIZARDFIELDCOUNT,
218: new Integer(colList.size()));
219: table.setProperty(PropertyKeys.WIZARDRECORDLENGTH,
220: new Integer(recLength));
221: }
222: }
223:
224: private void assertRecordLength(int recordLength, int fieldCount)
225: throws FlatfileDBException {
226: if (recordLength <= 0) {
227: throw new FlatfileDBException(
228: "Record length must be greater than zero.");
229: }
230:
231: if (fieldCount > recordLength) {
232: throw new FlatfileDBException(
233: "Field count exceeds record length.");
234: }
235: }
236:
237: private List generateColumnNames(FlatfileDBTable table,
238: int columnCount, int jdbcType, int baseLength,
239: int remainderLength) throws FlatfileDBException {
240: FlatfileDBColumn[] columns = getColumns(table);
241: List colList = new ArrayList(columns.length);
242: for (int i = 1; i <= columnCount; i++) {
243: FlatfileDBColumn column = null;
244: if (columns != null && i <= columns.length) {
245: column = columns[i - 1];
246: }
247:
248: String columnName = "FIELD_" + i;
249: int precision = (i != columnCount) ? baseLength
250: : remainderLength;
251: if (column == null) {
252: column = new FlatfileDBColumnImpl(columnName, jdbcType,
253: precision, 0, true);
254: }
255:
256: column.setCardinalPosition(i);
257: colList.add(column);
258: }
259: return colList;
260: }
261:
262: private FlatfileDBColumn[] getColumns(FlatfileDBTable table) {
263: FlatfileDBColumn[] columns = new FlatfileDBColumn[0];
264: if (table.getColumnList().size() > 0) {
265: columns = (FlatfileDBColumn[]) table.getColumnList()
266: .toArray(columns);
267: }
268: return columns;
269: }
270:
271: private String getErrMessage(int fieldCount) {
272: StringBuilder errMsg = new StringBuilder(50);
273: if (fieldCount == 0) {
274: errMsg
275: .append("Field count must be a non-zero integer value.\n");
276: } else {
277: // Generic message.
278: errMsg
279: .append("Invalid length and/or field count values.\nPlease review and correct as necessary.");
280: }
281: return errMsg.toString();
282: }
283:
284: private List readHeaderFromFirstLine(FlatfileDBTable table,
285: int offset, int jdbcType, int recordlLength)
286: throws FlatfileDBException {
287: String filename = table.getFileName();
288: String encoding = table.getEncodingScheme();
289: FlatfileDBColumn[] columns = getColumns(table);
290: BufferedReader br = null;
291: String repFile = null;
292: final int maxCharsToRead = 500;
293: List colList = new ArrayList(columns.length);
294:
295: try {
296: repFile = table.getProperty(PropertyKeys.URL);
297: repFile = StringUtil.escapeControlChars(repFile);
298: File f = new File(repFile);
299: InputStream is = null;
300: if (f.exists()) {
301: is = new FileInputStream(f);
302: } else {
303: is = new URL(repFile).openStream();
304: }
305:
306: br = new BufferedReader(
307: new InputStreamReader(is, encoding),
308: maxCharsToRead * 5);
309:
310: char[] headerBytes = new char[recordlLength];
311:
312: if (br.skip(offset) != offset) {
313: throw new FlatfileDBException("No header found");
314: }
315:
316: if (br.read(headerBytes) != recordlLength) {
317: throw new FlatfileDBException("Unable to read header");
318: }
319:
320: String headerStr = new String(headerBytes);
321: String columnNames[] = headerStr.split("\\W+");
322:
323: if (columnNames.length == 0) {
324: throw new FlatfileDBException("No header found");
325: }
326:
327: for (int i = 1; i <= columnNames.length; i++) {
328: int precision;
329: if (i == columnNames.length) { // remainderLength
330: precision = recordlLength
331: - headerStr.indexOf(columnNames[i - 1]);
332: } else if (i == 1) { // first column
333: precision = headerStr.indexOf(columnNames[1]);
334: } else {
335: precision = headerStr.indexOf(columnNames[i])
336: - headerStr.indexOf(columnNames[i - 1]);
337: }
338:
339: FlatfileDBColumn column = null;
340: if (columns != null && i <= columns.length) {
341: column = columns[i - 1];
342: }
343:
344: String columnName = StringUtil
345: .createColumnNameFromFieldName(columnNames[i - 1]);
346: if (column == null) {
347: column = new FlatfileDBColumnImpl(columnName,
348: jdbcType, precision, 0, true);
349:
350: } else {
351: column.setName(columnName);
352: column.setPrecision(precision);
353: }
354:
355: column.setCardinalPosition(i);
356: colList.add(column);
357: }
358: return colList;
359: } catch (IOException ioe) {
360: throw new FlatfileDBException(ioe.getMessage(), ioe);
361: } finally {
362: if (br != null) {
363: try {
364: br.close();
365: } catch (IOException ignore) {
366: // ignore
367: }
368: }
369: }
370: }
371:
372: }
|