Original 2.4
[marc4j.git] / src / org / marc4j / MarcStreamWriter.java
1 // $Id: MarcStreamWriter.java,v 1.4 2006/08/04 12:24:05 bpeters Exp $\r
2 /**\r
3  * Copyright (C) 2004 Bas Peters\r
4  *\r
5  * This file is part of MARC4J\r
6  *\r
7  * MARC4J is free software; you can redistribute it and/or\r
8  * modify it under the terms of the GNU Lesser General Public \r
9  * License as published by the Free Software Foundation; either \r
10  * version 2.1 of the License, or (at your option) any later version.\r
11  *\r
12  * MARC4J is distributed in the hope that it will be useful,\r
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
15  * Lesser General Public License for more details.\r
16  *\r
17  * You should have received a copy of the GNU Lesser General Public \r
18  * License along with MARC4J; if not, write to the Free Software\r
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
20  */\r
21 package org.marc4j;\r
22 \r
23 import java.io.ByteArrayOutputStream;\r
24 import java.io.IOException;\r
25 import java.io.OutputStream;\r
26 import java.text.DecimalFormat;\r
27 import java.util.Iterator;\r
28 import java.util.List;\r
29 \r
30 import org.marc4j.converter.CharConverter;\r
31 import org.marc4j.marc.ControlField;\r
32 import org.marc4j.marc.DataField;\r
33 import org.marc4j.marc.Leader;\r
34 import org.marc4j.marc.Record;\r
35 import org.marc4j.marc.Subfield;\r
36 \r
37 /**\r
38  * Class for writing MARC record objects in ISO 2709 format.\r
39  * \r
40  * <p>\r
41  * The following example reads a file with MARCXML records and outputs the\r
42  * record set in ISO 2709 format:\r
43  * </p>\r
44  * \r
45  * <pre>\r
46  * InputStream input = new FileInputStream(&quot;marcxml.xml&quot;);\r
47  * MarcXmlReader reader = new MarcXmlReader(input);\r
48  * MarcWriter writer = new MarcStreamWriter(System.out);\r
49  * while (reader.hasNext()) {\r
50  *     Record record = reader.next();\r
51  *     writer.write(record);\r
52  * }\r
53  * writer.close();\r
54  * </pre>\r
55  * \r
56  * <p>\r
57  * To convert characters like for example from UCS/Unicode to MARC-8 register\r
58  * a {@link org.marc4j.converter.CharConverter}&nbsp;implementation:\r
59  * </p>\r
60  * \r
61  * <pre>\r
62  * InputStream input = new FileInputStream(&quot;marcxml.xml&quot;);\r
63  * MarcXmlReader reader = new MarcXmlReader(input);\r
64  * MarcWriter writer = new MarcStreamWriter(System.out);\r
65  * writer.setConverter(new UnicodeToAnsel());\r
66  * while (reader.hasNext()) {\r
67  *     Record record = reader.next();\r
68  *     writer.write(record);\r
69  * }\r
70  * writer.close();\r
71  * </pre>\r
72  * \r
73  * @author Bas Peters\r
74  * @version $Revision: 1.4 $\r
75  */\r
76 public class MarcStreamWriter implements MarcWriter {\r
77 \r
78     private OutputStream out = null;\r
79 \r
80     private String encoding = "ISO8859_1";\r
81 \r
82     private CharConverter converter = null;\r
83 \r
84     private static DecimalFormat format4 = new DecimalFormat("0000");\r
85 \r
86     private static DecimalFormat format5 = new DecimalFormat("00000");\r
87 \r
88     /**\r
89      * Constructs an instance and creates a <code>Writer</code> object with\r
90      * the specified output stream.\r
91      */\r
92     public MarcStreamWriter(OutputStream out) {\r
93         this.out = out;\r
94     }\r
95 \r
96     /**\r
97      * Constructs an instance and creates a <code>Writer</code> object with\r
98      * the specified output stream and character encoding.\r
99      */\r
100     public MarcStreamWriter(OutputStream out, String encoding) {\r
101         this.encoding = encoding;\r
102         this.out = out;\r
103     }\r
104 \r
105     /**\r
106      * Returns the character converter.\r
107      * \r
108      * @return CharConverter the character converter\r
109      */\r
110     public CharConverter getConverter() {\r
111         return converter;\r
112     }\r
113 \r
114     /**\r
115      * Sets the character converter.\r
116      * \r
117      * @param converter\r
118      *            the character converter\r
119      */\r
120     public void setConverter(CharConverter converter) {\r
121         this.converter = converter;\r
122     }\r
123 \r
124     /**\r
125      * Writes a <code>Record</code> object to the writer.\r
126      * \r
127      * @param record -\r
128      *            the <code>Record</code> object\r
129      */\r
130     public void write(Record record) {\r
131         int previous = 0;\r
132 \r
133         try {\r
134             ByteArrayOutputStream data = new ByteArrayOutputStream();\r
135             ByteArrayOutputStream dir = new ByteArrayOutputStream();\r
136 \r
137             // control fields\r
138             List fields = record.getControlFields();\r
139             Iterator i = fields.iterator();\r
140             while (i.hasNext()) {\r
141                 ControlField cf = (ControlField) i.next();\r
142 \r
143                 data.write(getDataElement(cf.getData()));\r
144                 data.write(Constants.FT);\r
145                 dir.write(getEntry(cf.getTag(), data.size() - previous,\r
146                         previous));\r
147                 previous = data.size();\r
148             }\r
149 \r
150             // data fields\r
151             fields = record.getDataFields();\r
152             i = fields.iterator();\r
153             while (i.hasNext()) {\r
154                 DataField df = (DataField) i.next();\r
155                 data.write(df.getIndicator1());\r
156                 data.write(df.getIndicator2());\r
157                 List subfields = df.getSubfields();\r
158                 Iterator si = subfields.iterator();\r
159                 while (si.hasNext()) {\r
160                     Subfield sf = (Subfield) si.next();\r
161                     data.write(Constants.US);\r
162                     data.write(sf.getCode());\r
163                     data.write(getDataElement(sf.getData()));\r
164                 }\r
165                 data.write(Constants.FT);\r
166                 dir.write(getEntry(df.getTag(), data.size() - previous,\r
167                         previous));\r
168                 previous = data.size();\r
169             }\r
170             dir.write(Constants.FT);\r
171 \r
172             // base address of data and logical record length\r
173             Leader ldr = record.getLeader();\r
174 \r
175             ldr.setBaseAddressOfData(24 + dir.size());\r
176             ldr.setRecordLength(ldr.getBaseAddressOfData() + data.size() + 1);\r
177 \r
178             // write record to output stream\r
179             dir.close();\r
180             data.close();\r
181             write(ldr);\r
182             out.write(dir.toByteArray());\r
183             out.write(data.toByteArray());\r
184             out.write(Constants.RT);\r
185 \r
186         } catch (IOException e) {\r
187             throw new MarcException("IO Error occured while writing record", e);\r
188         }\r
189     }\r
190 \r
191     private void write(Leader ldr) throws IOException {\r
192         out.write(format5.format(ldr.getRecordLength()).getBytes(encoding));\r
193         out.write(ldr.getRecordStatus());\r
194         out.write(ldr.getTypeOfRecord());\r
195         out.write(new String(ldr.getImplDefined1()).getBytes(encoding));\r
196         out.write(ldr.getCharCodingScheme());\r
197         out.write(Integer.toString(ldr.getIndicatorCount()).getBytes(encoding));\r
198         out.write(Integer.toString(ldr.getSubfieldCodeLength()).getBytes(\r
199                 encoding));\r
200         out\r
201                 .write(format5.format(ldr.getBaseAddressOfData()).getBytes(\r
202                         encoding));\r
203         out.write(new String(ldr.getImplDefined2()).getBytes(encoding));\r
204         out.write(new String(ldr.getEntryMap()).getBytes(encoding));\r
205     }\r
206 \r
207     /**\r
208      * Closes the writer.\r
209      */\r
210     public void close() {\r
211         try {\r
212             out.close();\r
213         } catch (IOException e) {\r
214             throw new MarcException("IO Error occured on close", e);\r
215         }\r
216     }\r
217 \r
218     private byte[] getDataElement(String data) throws IOException {\r
219         if (converter != null)\r
220             return converter.convert(data).getBytes(encoding);\r
221         return data.getBytes(encoding);\r
222     }\r
223 \r
224     private byte[] getEntry(String tag, int length, int start)\r
225             throws IOException {\r
226         return (tag + format4.format(length) + format5.format(start))\r
227                 .getBytes(encoding);\r
228     }\r
229 }