View Javadoc

1   package net.sf.cobol2j;
2   
3   import net.sf.cobol2j.FieldFormat;
4   import net.sf.cobol2j.FieldsGroup;
5   import net.sf.cobol2j.FieldsList;
6   import net.sf.cobol2j.FileFormat;
7   import net.sf.cobol2j.FileFormatException;
8   import net.sf.cobol2j.RecordFormat;
9   import net.sf.cobol2j.RecordSet;
10  
11  import org.apache.commons.lang.mutable.MutableInt;
12  import org.apache.commons.logging.Log;
13  import org.apache.commons.logging.LogFactory;
14  
15  import java.io.FileInputStream;
16  import java.io.FileNotFoundException;
17  import java.io.FileOutputStream;
18  import java.io.IOException;
19  import java.io.OutputStream;
20  import java.io.OutputStreamWriter;
21  import java.io.UnsupportedEncodingException;
22  
23  import java.math.BigDecimal;
24  import java.math.BigInteger;
25  
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Map;
30  
31  
32  public class RecordWriter {
33      private static Log log = LogFactory.getLog(RecordWriter.class);
34      OutputStream oS;
35      String charset;
36      Map recdefs;
37  
38      public RecordWriter(OutputStream os, FileFormat ff)
39          throws UnsupportedEncodingException {
40          oS = os;
41          charset = ff.getConversionTable();
42          recdefs = new RecordsMap(ff);
43      }
44  
45      public void writeRecord(List fields) throws Exception {
46          RecordFormat rF = (RecordFormat) recdefs.get("0");
47  
48          if (recdefs.size() > 1) {
49              String first1 = fields.get(0).toString();
50              rF = (RecordFormat) recdefs.get(first1);
51          }
52  
53          Iterator data = fields.listIterator();
54          createFields(data, rF);
55      }
56  
57      private void createFields(Iterator data, FieldsList deflist)
58          throws Exception {
59          HashMap potentialDepOn = new HashMap();
60          Iterator def = deflist.getFieldFormatOrFieldsGroup().listIterator();
61  
62          while (def.hasNext()) {
63              Object u = def.next();
64  
65              if (u instanceof FieldFormat) {
66                  int occurs = 1;
67                  FieldFormat ff = (FieldFormat) u;
68                  String dependingon = ff.getDependingOn();
69  
70                  if (dependingon.length() > 0) {
71                      BigDecimal bd = (BigDecimal) potentialDepOn.get(dependingon);
72                      occurs = bd.intValue();
73                  } else {
74                      occurs = ff.getOccurs().intValue();
75                  }
76  
77                  while (occurs-- > 0) {
78                      Object o = data.next();
79                      writeField(o, ff, potentialDepOn);
80                  }
81              } else if (u instanceof FieldsGroup) {
82                  int occurs = 1;
83                  FieldsGroup fG = (FieldsGroup) u;
84                  String dependingon = fG.getDependingOn();
85  
86                  if (dependingon.length() > 0) {
87                      BigDecimal bd = (BigDecimal) potentialDepOn.get(dependingon);
88                      occurs = bd.intValue();
89                  } else {
90                      occurs = fG.getOccurs().intValue();
91                  }
92  
93                  while (occurs-- > 0) {
94                      createFields(data, fG);
95                  }
96              }
97          }
98      }
99  
100     private void writeField(Object o, FieldFormat format, HashMap potDepOn)
101         throws IOException, Exception {
102         char fType = format.getType().charAt(0);
103 
104         switch (fType) {
105         case 'X':
106 
107             if (o instanceof String) {
108                 String value = (String) o;
109 
110                 if (value.length() != format.getSize().intValue()) {
111                     throw new Exception(
112                         "Value size must be equal to field length.");
113                 }
114 
115                 oS.write(value.getBytes(charset));
116             } else {
117                 throw new Exception("ValueTypeMismatch");
118             }
119 
120             break;
121 
122         case '9':
123 
124             if (o instanceof BigDecimal) {
125                 BigDecimal value = (BigDecimal) o;
126 
127                 if (format.getDecimal().intValue() != value.scale()) {
128                     BigDecimal tmp = value.setScale(format.getDecimal()
129                                                           .intValue(),
130                             BigDecimal.ROUND_FLOOR);
131                     value = tmp;
132                 }
133 
134                 String str = value.toPlainString();
135                 StringBuffer buf = new StringBuffer(str);
136 
137                 // Modify byte with sign ...
138                 if (format.isSigned()) {
139                     int lastidx = buf.length() - 1;
140                     char lastbyte = buf.charAt(lastidx);
141                     char repl;
142 
143                     if (value.signum() > 0) {
144                         repl = "{ABCDEFGHI".charAt(Integer.parseInt(
145                                     String.valueOf(lastbyte)));
146                     } else {
147                         repl = "}JKLMNOPQR".charAt(Integer.parseInt(
148                                     String.valueOf(lastbyte)));
149                     }
150 
151                     buf.setCharAt(lastidx, repl);
152 
153                     // Delete sign char
154                     String tmp = buf.toString();
155                     String tmp2 = tmp.replace("-", "");
156                     buf = new StringBuffer(tmp2);
157                 }
158 
159                 // Delete decimal point...
160                 if (format.isImpliedDecimal()) {
161                     String tmp = buf.toString();
162                     String tmp2 = tmp.replace(".", "");
163                     buf = new StringBuffer(tmp2);
164                 }
165 
166                 // Adding some leading zeros ...
167                 while (format.getSize().intValue() > buf.length()) {
168                     buf.insert(0, "0");
169                 }
170 
171                 oS.write(buf.toString().getBytes(charset));
172                 potDepOn.put(format.getName(), value);
173             } else {
174                 throw new Exception("ValueTypeMismatch");
175             }
176 
177             break;
178 
179         case '3':
180 
181             if (o instanceof BigDecimal) {
182                 BigDecimal value = (BigDecimal) o;
183 
184                 if (format.getDecimal().intValue() != value.scale()) {
185                     BigDecimal tmp = value.setScale(format.getDecimal()
186                                                           .intValue(),
187                             BigDecimal.ROUND_FLOOR);
188                     value = tmp;
189                 }
190 
191                 String str = value.toPlainString();
192                 int len = str.length();
193                 int fieldSize = getByteSize(format);
194                 byte[] buf = new byte[fieldSize];
195                 MutableInt k = new MutableInt(len);
196                 byte even; // left and right nibble ( we go from right to left )
197                 byte odd;
198 
199                 for (int i = fieldSize - 1; i >= 0; i--) {
200                     // Last byte needs sign nibble
201                     if (i == (fieldSize - 1)) {
202                         even = getNextByte(str, k);
203 
204                         if (format.isSigned()) {
205                             if (value.signum() >= 0) {
206                                 odd = 0x0C;
207                             } else {
208                                 odd = 0x0D;
209                             }
210                         } else {
211                             odd = (byte) 0x0F;
212                         }
213                     } else {
214                         // Packing rest of the digits...
215                         // Get even digit if exist or zero
216                         odd = getNextByte(str, k);
217                         even = getNextByte(str, k);
218                     }
219 
220                     buf[i] = (byte) ((even << 4) | odd);
221                 }
222 
223                 // TODO: Check if str ">" buf and eventually throw an Exc.
224                 oS.write(buf);
225             } else {
226                 throw new Exception("ValueTypeMismatch");
227             }
228 
229             break;
230 
231         case 'B':
232 
233             if (o instanceof BigDecimal) {
234                 BigDecimal value = (BigDecimal) o;
235 
236                 if (format.getDecimal().intValue() != value.scale()) {
237                     BigDecimal tmp = value.setScale(format.getDecimal()
238                                                           .intValue(),
239                             BigDecimal.ROUND_FLOOR);
240                     value = tmp;
241                 }
242 
243                 BigInteger unscaled = value.unscaledValue();
244 
245                 // TODO: Requires trimming to environment dependent bytesize
246                 oS.write(unscaled.toByteArray());
247             } else {
248                 throw new Exception("ValueTypeMismatch");
249             }
250 
251             break;
252 
253         case 'T':
254 
255             if (o instanceof byte[]) {
256                 byte[] value = (byte[]) o;
257 
258                 if (value.length == format.getSize().intValue()) {
259                     oS.write(value);
260                 } else {
261                     throw new Exception(
262                         "Value size must be equal to field length.");
263                 }
264             } else {
265                 throw new Exception("ValueTypeMismatch");
266             }
267 
268             break;
269 
270         default:
271             throw new FileFormatException("Field type not supported: " + fType);
272         }
273     }
274 
275     private int getByteSize(FieldFormat fieldF) {
276         int sz = fieldF.getSize().intValue();
277 
278         if (fieldF.getType().equals("3")) {
279             if ((sz % 2) != 0) {
280                 return (sz / 2) + 1;
281             } else {
282                 return sz / 2;
283             }
284         } else {
285             return sz;
286         }
287     }
288 
289     private byte getNextByte(String number, MutableInt recentlyReturned) {
290         MutableInt zero = new MutableInt(0);
291         recentlyReturned.decrement();
292 
293         if (recentlyReturned.compareTo(zero) >= 0) {
294             while (!"0123456789".contains(String.valueOf(number.charAt(
295                                 recentlyReturned.intValue())))) {
296                 recentlyReturned.decrement();
297 
298                 if (recentlyReturned.compareTo(zero) < 0) {
299                     return 0;
300                 }
301             }
302 
303             return (byte) (Character.getNumericValue(number.charAt(
304                     recentlyReturned.intValue())));
305         } else {
306             return 0;
307         }
308     }
309 }