KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ofbiz > datafile > Record


1 /*
2  * $Id: Record.java 5462 2005-08-05 18:35:48Z jonesde $
3  *
4  * Copyright (c) 2001-2003 The Open For Business Project - www.ofbiz.org
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  */

25 package org.ofbiz.datafile;
26
27 import java.io.Serializable JavaDoc;
28 import java.text.NumberFormat JavaDoc;
29 import java.text.ParseException JavaDoc;
30 import java.text.SimpleDateFormat JavaDoc;
31 import java.util.ArrayList JavaDoc;
32 import java.util.Date JavaDoc;
33 import java.util.HashMap JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.StringTokenizer JavaDoc;
37 import java.util.NoSuchElementException JavaDoc;
38
39 /**
40  * Record
41  *
42  * @author <a HREF="mailto:jonesde@ofbiz.org">David E. Jones</a>
43  * @version $Rev: 5462 $
44  * @since 2.0
45  */

46 public class Record implements Serializable JavaDoc {
47
48     /** Contains a map with field data by name */
49     protected Map JavaDoc fields;
50
51     /** Contains the name of the record definition */
52     protected String JavaDoc recordName;
53
54     /** Contains the definition for the record */
55     protected transient ModelRecord modelRecord;
56
57     protected Record parentRecord = null;
58     protected List JavaDoc childRecords = new ArrayList JavaDoc();
59
60     /** Creates new Record */
61     protected Record(ModelRecord modelRecord) {
62         if (modelRecord == null)
63             throw new IllegalArgumentException JavaDoc("Cannont create a Record with a null modelRecord parameter");
64         this.recordName = modelRecord.name;
65         this.modelRecord = modelRecord;
66         this.fields = new HashMap JavaDoc();
67     }
68
69     /** Creates new Record from existing Map */
70     protected Record(ModelRecord modelRecord, Map JavaDoc fields) {
71         if (modelRecord == null)
72             throw new IllegalArgumentException JavaDoc("Cannont create a Record with a null modelRecord parameter");
73         this.recordName = modelRecord.name;
74         this.modelRecord = modelRecord;
75         this.fields = (fields == null ? new HashMap JavaDoc() : new HashMap JavaDoc(fields));
76     }
77
78     public String JavaDoc getRecordName() {
79         return recordName;
80     }
81
82     public ModelRecord getModelRecord() {
83         if (modelRecord == null) {
84             throw new IllegalStateException JavaDoc("[Record.getModelRecord] could not find modelRecord for recordName " + recordName);
85         }
86         return modelRecord;
87     }
88
89     public Object JavaDoc get(String JavaDoc name) {
90         if (getModelRecord().getModelField(name) == null) {
91             throw new IllegalArgumentException JavaDoc("[Record.get] \"" + name + "\" is not a field of " + recordName);
92             // Debug.logWarning("[GenericRecord.get] \"" + name + "\" is not a field of " + recordName + ", but getting anyway...", module);
93
}
94         return fields.get(name);
95     }
96
97     public String JavaDoc getString(String JavaDoc name) {
98         Object JavaDoc object = get(name);
99
100         if (object == null)
101             return null;
102         if (object instanceof java.lang.String JavaDoc)
103             return (String JavaDoc) object;
104         else
105             return object.toString();
106     }
107
108     public java.sql.Timestamp JavaDoc getTimestamp(String JavaDoc name) {
109         return (java.sql.Timestamp JavaDoc) get(name);
110     }
111
112     public java.sql.Time JavaDoc getTime(String JavaDoc name) {
113         return (java.sql.Time JavaDoc) get(name);
114     }
115
116     public java.sql.Date JavaDoc getDate(String JavaDoc name) {
117         return (java.sql.Date JavaDoc) get(name);
118     }
119
120     public Integer JavaDoc getInteger(String JavaDoc name) {
121         return (Integer JavaDoc) get(name);
122     }
123
124     public Long JavaDoc getLong(String JavaDoc name) {
125         return (Long JavaDoc) get(name);
126     }
127
128     public Float JavaDoc getFloat(String JavaDoc name) {
129         return (Float JavaDoc) get(name);
130     }
131
132     public Double JavaDoc getDouble(String JavaDoc name) {
133         return (Double JavaDoc) get(name);
134     }
135
136     /** Sets the named field to the passed value, even if the value is null
137      * @param name The field name to set
138      * @param value The value to set
139      */

140     public void set(String JavaDoc name, Object JavaDoc value) {
141         set(name, value, true);
142     }
143
144     /** Sets the named field to the passed value. If value is null, it is only
145      * set if the setIfNull parameter is true.
146      * @param name The field name to set
147      * @param value The value to set
148      * @param setIfNull Specifies whether or not to set the value if it is null
149      */

150     public synchronized void set(String JavaDoc name, Object JavaDoc value, boolean setIfNull) {
151         if (getModelRecord().getModelField(name) == null) {
152             throw new IllegalArgumentException JavaDoc("[Record.set] \"" + name + "\" is not a field of " + recordName);
153             // Debug.logWarning("[GenericRecord.set] \"" + name + "\" is not a field of " + recordName + ", but setting anyway...", module);
154
}
155         if (value != null || setIfNull) {
156             if (value instanceof Boolean JavaDoc) {
157                 value = ((Boolean JavaDoc) value).booleanValue() ? "Y" : "N";
158             }
159             fields.put(name, value);
160         }
161     }
162
163     /**
164      * little endian reader for 2 byte short.
165      */

166     public final short readLEShort(byte[] byteArray) {
167         return (short)(
168                (byteArray[1]&0xff) << 8 |
169                (byteArray[0]&0xff));
170
171     }
172
173     /**
174      * little endian reader for 4 byte int.
175      */

176     public final int readLEInt(byte []byteArray) {
177         return
178         (byteArray[3]) << 24 |
179         (byteArray[2]&0xff) << 16 |
180         (byteArray[1]&0xff) << 8 |
181         (byteArray[0]&0xff);
182     }
183
184     /**
185     * little endian reader for 8 byte long.
186     */

187     public final long readLELong(byte []byteArray) {
188        return
189            (long)(byteArray[7]) << 56 | /* long cast needed or shift done modulo 32 */
190            (long)(byteArray[6]&0xff) << 48 |
191            (long)(byteArray[5]&0xff) << 40 |
192            (long)(byteArray[4]&0xff) << 32 |
193            (long)(byteArray[3]&0xff) << 24 |
194            (long)(byteArray[2]&0xff) << 16 |
195            (long)(byteArray[1]&0xff) << 8 |
196            (long)(byteArray[0]&0xff);
197     }
198
199     /** Sets the named field to the passed value, converting the value from a String to the corrent type using <code>Type.valueOf()</code>
200      * @param name The field name to set
201      * @param value The String value to convert and set
202      */

203     public void setString(String JavaDoc name, String JavaDoc value) throws ParseException JavaDoc {
204         if (name == null || value == null || value.equals(""))
205             return;
206         ModelField field = getModelRecord().getModelField(name);
207
208         if (field == null)
209             set(name, value); // this will get an error in the set() method...
210

211         // if the string is all spaces ignore
212
boolean nonSpace = false;
213
214         for (int i = 0; i < value.length(); i++) {
215             if (value.charAt(i) != ' ') {
216                 nonSpace = true;
217                 break;
218             }
219         }
220         if (!nonSpace)
221             return;
222
223         // if (Debug.verboseOn()) Debug.logVerbose("Value: " + value, module);
224

225         String JavaDoc fieldType = field.type;
226
227         // first the custom types that need to be parsed
228
if (fieldType.equals("CustomTimestamp")) {
229             // this custom type will take a string a parse according to date formatting
230
// string then put the result in a java.sql.Timestamp
231
// a common timestamp format for flat files is with no separators: yyyyMMddHHmmss
232
SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc(field.format);
233             java.util.Date JavaDoc tempDate = sdf.parse(value);
234             java.sql.Timestamp JavaDoc timestamp = new java.sql.Timestamp JavaDoc(tempDate.getTime());
235
236             set(name, timestamp);
237         } else if (fieldType.equals("CustomDate")) {
238             // a common date only format for flat files is with no separators: yyyyMMdd or MMddyyyy
239
SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc(field.format);
240             java.util.Date JavaDoc tempDate = sdf.parse(value);
241             java.sql.Date JavaDoc date = new java.sql.Date JavaDoc(tempDate.getTime());
242
243             set(name, date);
244         } else if (fieldType.equals("CustomTime")) {
245             // a common time only format for flat files is with no separators: HHmmss
246
SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc(field.format);
247             java.util.Date JavaDoc tempDate = sdf.parse(value);
248             java.sql.Time JavaDoc time = new java.sql.Time JavaDoc(tempDate.getTime());
249
250             set(name, time);
251         } else if (fieldType.equals("FixedPointDouble")) {
252             // this custom type will parse a fixed point number according to the number
253
// of decimal places in the formatting string then place it in a Double
254
NumberFormat JavaDoc nf = NumberFormat.getNumberInstance();
255             Number JavaDoc tempNum = nf.parse(value);
256             double number = tempNum.doubleValue();
257             double decimalPlaces = Double.parseDouble(field.format);
258             double divisor = Math.pow(10.0, decimalPlaces);
259
260             number = number / divisor;
261             set(name, new Double JavaDoc(number));
262         } // standard types
263
else if (fieldType.equals("java.lang.String") || fieldType.equals("String"))
264             set(name, value);
265         else if (fieldType.equals("NullTerminatedString")) {
266             int terminate = value.indexOf(0x0);
267             set(name, terminate>0?value.substring(0,terminate):value);
268         } else if (fieldType.equals("java.sql.Timestamp") || fieldType.equals("Timestamp"))
269             set(name, java.sql.Timestamp.valueOf(value));
270         else if (fieldType.equals("java.sql.Time") || fieldType.equals("Time"))
271             set(name, java.sql.Time.valueOf(value));
272         else if (fieldType.equals("java.sql.Date") || fieldType.equals("Date"))
273             set(name, java.sql.Date.valueOf(value));
274         else if (fieldType.equals("java.lang.Integer") || fieldType.equals("Integer"))
275             set(name, Integer.valueOf(value));
276         else if (fieldType.equals("java.lang.Long") || fieldType.equals("Long"))
277             set(name, Long.valueOf(value));
278         else if (fieldType.equals("java.lang.Float") || fieldType.equals("Float"))
279             set(name, Float.valueOf(value));
280         else if (fieldType.equals("java.lang.Double") || fieldType.equals("Double"))
281             set(name, Double.valueOf(value));
282         else if (fieldType.equals("LEShort"))
283             set(name, new Short JavaDoc(readLEShort(value.getBytes())));
284         else if (fieldType.equals("LEInteger"))
285             set(name, new Integer JavaDoc(readLEInt(value.getBytes())));
286         else if (fieldType.equals("LELong"))
287             set(name, new Long JavaDoc(readLELong(value.getBytes())));
288        else {
289             throw new IllegalArgumentException JavaDoc("Field type " + fieldType + " not currently supported. Sorry.");
290         }
291     }
292
293     public String JavaDoc getFixedString(String JavaDoc name) {
294         if (name == null)
295             return null;
296         if (getModelRecord() == null)
297             throw new IllegalArgumentException JavaDoc("Could not find modelrecord for field named \"" + name + "\"");
298         ModelField field = getModelRecord().getModelField(name);
299
300         if (field == null)
301             throw new IllegalArgumentException JavaDoc("Could not find model for field named \"" + name + "\"");
302
303         Object JavaDoc value = get(name);
304
305         if (value == null) {
306             return null;
307         }
308
309         String JavaDoc fieldType = field.type;
310         String JavaDoc str = null;
311
312         // first the custom types that need to be parsed
313
if (fieldType.equals("CustomTimestamp")) {
314             // a common timestamp format for flat files is with no separators: yyyyMMddHHmmss
315
SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc(field.format);
316             java.sql.Timestamp JavaDoc timestamp = (java.sql.Timestamp JavaDoc) value;
317
318             str = sdf.format(new Date JavaDoc(timestamp.getTime()));
319         } else if (fieldType.equals("CustomDate")) {
320             // a common date only format for flat files is with no separators: yyyyMMdd or MMddyyyy
321
SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc(field.format);
322             java.sql.Date JavaDoc date = (java.sql.Date JavaDoc) value;
323
324             str = sdf.format(new Date JavaDoc(date.getTime()));
325         } else if (fieldType.equals("CustomTime")) {
326             // a common time only format for flat files is with no separators: HHmmss
327
SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc(field.format);
328             java.sql.Time JavaDoc time = (java.sql.Time JavaDoc) value;
329
330             str = sdf.format(new Date JavaDoc(time.getTime()));
331         } else if (fieldType.equals("FixedPointDouble")) {
332             // this custom type will parse a fixed point number according to the number
333
// of decimal places in the formatting string then place it in a Double
334
NumberFormat JavaDoc nf = NumberFormat.getNumberInstance();
335             double decimalPlaces = Double.parseDouble(field.format);
336             double multiplier = Math.pow(10.0, decimalPlaces);
337             double dnum = multiplier * ((Double JavaDoc) value).doubleValue();
338             long number = Math.round(dnum);
339
340             str = padFrontZeros(Long.toString(number), field.length);
341             // if (Debug.infoOn()) Debug.logInfo("[Record.getFixedString] FixedPointDouble: multiplier=" + multiplier + ", value=" + value + ", dnum=" + dnum + ", number=" + number + ", str=" + str, module);
342
} // standard types
343
else if (fieldType.equals("java.lang.String") || fieldType.equals("String"))
344             str = value.toString();
345         else if (fieldType.equals("java.sql.Timestamp") || fieldType.equals("Timestamp"))
346             str = value.toString();
347         else if (fieldType.equals("java.sql.Time") || fieldType.equals("Time"))
348             str = value.toString();
349         else if (fieldType.equals("java.sql.Date") || fieldType.equals("Date"))
350             str = value.toString();
351         // for all numbers, pad front with zeros if field length is specified
352
else if (fieldType.equals("java.lang.Integer") || fieldType.equals("Integer"))
353             str = padFrontZeros(value.toString(), field.length);
354         else if (fieldType.equals("java.lang.Long") || fieldType.equals("Long"))
355             str = padFrontZeros(value.toString(), field.length);
356         else if (fieldType.equals("java.lang.Float") || fieldType.equals("Float"))
357             str = padFrontZeros(value.toString(), field.length);
358         else if (fieldType.equals("java.lang.Double") || fieldType.equals("Double"))
359             str = padFrontZeros(value.toString(), field.length);
360         else {
361             throw new IllegalArgumentException JavaDoc("Field type " + fieldType + " not currently supported. Sorry.");
362         }
363
364         if (str != null && field.length > 0 && str.length() < field.length) {
365             // pad the end with spaces
366
StringBuffer JavaDoc strBuf = new StringBuffer JavaDoc(str);
367
368             while (strBuf.length() < field.length)
369                 strBuf.append(' ');
370             str = strBuf.toString();
371         }
372         return str;
373     }
374
375     public String JavaDoc writeLineString(ModelDataFile modelDataFile) throws DataFileException {
376         ModelRecord modelRecord = getModelRecord();
377         boolean isFixedRecord = ModelDataFile.SEP_FIXED_RECORD.equals(modelDataFile.separatorStyle);
378         boolean isFixedLength = ModelDataFile.SEP_FIXED_LENGTH.equals(modelDataFile.separatorStyle);
379         boolean isDelimited = ModelDataFile.SEP_DELIMITED.equals(modelDataFile.separatorStyle);
380
381         StringBuffer JavaDoc lineBuf = new StringBuffer JavaDoc();
382
383         for (int f = 0; f < modelRecord.fields.size(); f++) {
384             ModelField modelField = (ModelField) modelRecord.fields.get(f);
385             String JavaDoc data = this.getFixedString(modelField.name);
386
387             // if field is null (not set) then assume we want to pad the field
388
char PAD_CHAR = ' ';
389
390             if (data == null) {
391                 StringBuffer JavaDoc sb = new StringBuffer JavaDoc("");
392
393                 for (int i = 0; i < modelField.length; i++)
394                     sb.append(PAD_CHAR);
395                 data = new String JavaDoc(sb);
396             }
397
398             // Pad the record
399
if (isFixedRecord) {
400                 while (modelField.position > lineBuf.length())
401                     lineBuf.append(" ");
402             }
403             // if (Debug.infoOn()) Debug.logInfo("Field: " + modelField.name + " Position: " + modelField.position + " BufLen: " + lineBuf.length(), module);
404

405             // if (Debug.infoOn()) Debug.logInfo("Got data \"" + data + "\" for field " + modelField.name + " in record " + modelRecord.name, module);
406
if (modelField.length > 0 && data.length() != modelField.length)
407                 throw new DataFileException("Got field length " + data.length() + " but expected field length is " + modelField.length + " for field \"" +
408                         modelField.name + "\" of record \"" + modelRecord.name + "\" data is: \"" + data + "\"");
409
410             lineBuf.append(data);
411             if (isDelimited)
412                 lineBuf.append(modelDataFile.delimiter);
413         }
414         if ((isFixedRecord || isFixedLength) && modelDataFile.recordLength > 0 && lineBuf.length() != modelDataFile.recordLength)
415             throw new DataFileException("Got record length " + lineBuf.length() + " but expected record length is " + modelDataFile.recordLength +
416                     " for record \"" + modelRecord.name + "\" data line is: \"" + lineBuf + "\"");
417
418         // for convenience, insert the type-code in where it is looked for, if exists
419
if (modelRecord.tcPosition > 0 && modelRecord.typeCode.length() > 0) {
420             lineBuf.replace(modelRecord.tcPosition, modelRecord.tcPosition + modelRecord.tcLength, modelRecord.typeCode);
421         }
422
423         if (isFixedLength || isDelimited)
424             lineBuf.append('\n');
425
426         return lineBuf.toString();
427     }
428
429     String JavaDoc padFrontZeros(String JavaDoc str, int totalLength) {
430         if (totalLength > 0 && str.length() < totalLength) {
431             // pad the front with zeros
432
StringBuffer JavaDoc zeros = new StringBuffer JavaDoc();
433             int numZeros = totalLength - str.length();
434
435             for (int i = 0; i < numZeros; i++)
436                 zeros.append('0');
437             zeros.append(str);
438             return zeros.toString();
439         } else
440             return str;
441     }
442
443     public Record getParentRecord() {
444         return parentRecord;
445     }
446
447     public List JavaDoc getChildRecords() {
448         return childRecords;
449     }
450
451     public void addChildRecord(Record record) {
452         childRecords.add(record);
453     }
454
455     /** Creates new Record
456      * @param modelRecord
457      * @throws DataFileException Exception thown for various errors, generally has a nested exception
458      * @return
459      */

460     public static Record createRecord(ModelRecord modelRecord) throws DataFileException {
461         Record record = new Record(modelRecord);
462
463         return record;
464     }
465
466     /** Creates new Record from existing fields Map
467      * @param modelRecord
468      * @param fields
469      * @throws DataFileException Exception thown for various errors, generally has a nested exception
470      * @return
471      */

472     public static Record createRecord(ModelRecord modelRecord, Map JavaDoc fields) throws DataFileException {
473         Record record = new Record(modelRecord, fields);
474
475         return record;
476     }
477
478     /**
479      * @param line
480      * @param lineNum
481      * @param modelRecord
482      * @throws DataFileException Exception thown for various errors, generally has a nested exception
483      * @return
484      */

485     public static Record createRecord(String JavaDoc line, int lineNum, ModelRecord modelRecord) throws DataFileException {
486         Record record = new Record(modelRecord);
487
488         for (int i = 0; i < modelRecord.fields.size(); i++) {
489             ModelField modelField = (ModelField) modelRecord.fields.get(i);
490             String JavaDoc strVal = null;
491
492             
493             try {
494                 strVal = line.substring(modelField.position, modelField.position + modelField.length);
495             } catch (IndexOutOfBoundsException JavaDoc ioobe) {
496                 throw new DataFileException("Field " + modelField.name + " from " + modelField.position +
497                         " for " + modelField.length + " chars could not be read from a line (" + lineNum + ") with only " +
498                         line.length() + " chars.", ioobe);
499             }
500             try {
501                 record.setString(modelField.name, strVal);
502             } catch (java.text.ParseException JavaDoc e) {
503                 throw new DataFileException("Could not parse field " + modelField.name + ", format string \"" + modelField.format + "\" with value " + strVal +
504                         " on line " + lineNum, e);
505             } catch (java.lang.NumberFormatException JavaDoc e) {
506                 throw new DataFileException("Number not valid for field " + modelField.name + ", format string \"" + modelField.format + "\" with value " +
507                         strVal + " on line " + lineNum, e);
508             }
509         }
510         return record;
511     }
512     
513     /**
514      * @param line
515      * @param lineNum
516      * @param modelRecord
517      * @param delimiter
518      * @throws DataFileException Exception thown for various errors, generally has a nested exception
519      * @return
520      */

521     public static Record createDelimitedRecord(String JavaDoc line, int lineNum, ModelRecord modelRecord, char delimiter) throws DataFileException {
522         Record record = new Record(modelRecord);
523
524         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(line, "" + delimiter, true);
525         for (int i = 0; i < modelRecord.fields.size(); i++) {
526             ModelField modelField = (ModelField) modelRecord.fields.get(i);
527             String JavaDoc strVal = null;
528
529             if (modelField.expression) {
530                 if (modelField.refField != null && modelField.refField.length() > 0) {
531                     strVal = record.getString(modelField.refField);
532                 }
533                 if (strVal == null) {
534                     strVal = (String JavaDoc)modelField.defaultValue;
535                 }
536             } else {
537                 try {
538                     strVal = st.nextToken();
539                     if (strVal.equals("" + delimiter)) {
540                         strVal = null;
541                     } else {
542                         if (st.hasMoreTokens()) {
543                             st.nextToken();
544                         }
545                     }
546                 } catch (NoSuchElementException JavaDoc nsee) {
547                     throw new DataFileException("Field " + modelField.name + " could not be read from a line (" + lineNum + ") with only " +
548                             line.length() + " chars.", nsee);
549                 }
550             }
551             try {
552                 record.setString(modelField.name, strVal);
553             } catch (java.text.ParseException JavaDoc e) {
554                 throw new DataFileException("Could not parse field " + modelField.name + ", format string \"" + modelField.format + "\" with value " + strVal +
555                         " on line " + lineNum, e);
556             } catch (java.lang.NumberFormatException JavaDoc e) {
557                 throw new DataFileException("Number not valid for field " + modelField.name + ", format string \"" + modelField.format + "\" with value " +
558                         strVal + " on line " + lineNum, e);
559             }
560         }
561         return record;
562     }
563
564 }
565
566
Popular Tags