Original 2.4
[marc4j.git] / src / org / marc4j / ErrorHandler.java
1 // $Id: ErrorHandler.java,v 1.8 2008/10/17 06:47:06 haschart 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  */\r
22 package org.marc4j;\r
23 \r
24 import java.util.Iterator;\r
25 import java.util.LinkedList;\r
26 import java.util.List;\r
27 \r
28 /**\r
29  * Defines and describes errors encountered in the processing a given MARC record.\r
30  * Used in conjunction with the MarcPermissiveReader class. \r
31  *\r
32  * @author Robert Haschart\r
33  * @version $Revision: 1.8 $\r
34  */\r
35 public class ErrorHandler {\r
36 \r
37         /**\r
38          * FATAL is the most severe error, it is usually set in conjunction with throwing an\r
39          * exception, generally no record is returned when a FATAL error occurs.  Although in \r
40          * some instances (a record with a field > 9999 bytes long) a record will be returned \r
41          * that can be used, but it cannot be written back out without causing an error.\r
42          */ \r
43     public final static int FATAL = 4;\r
44 \r
45     /**\r
46          * MAJOR_ERROR indicates that a serious problem existed with the record, such as a \r
47          * malformed directory or an invalid subfield tag, or an encoding error where missing \r
48          * data had to be inferred through some heuristic process.  This indicates that \r
49          * although a record is returned, you cannot be sure that the record is not corrupted.\r
50          */ \r
51     public final static int MAJOR_ERROR = 3;\r
52     \r
53     /**\r
54          * MINOR_ERROR indicates that a less serious problem existed with the record, such as \r
55          * a mismatch between the directory stated field sizes and the actual field sizes, \r
56          * or an encoding error where extraneous data had to be discarded to correctly \r
57          * interpret the data.  \r
58          */ \r
59     public final static int MINOR_ERROR = 2;\r
60 \r
61     /**\r
62          * ERROR_TYPO indicates that an even less severe problem was found with the record,\r
63          * such as the record leader ends with characters other than "4500" or a field tag \r
64          * contains non-numeric characters the record contains a html-style entity reference \r
65          * such as & or &quote; which was replaced with the unescaped version. \r
66          */ \r
67     public final static int ERROR_TYPO = 1;\r
68  \r
69     /**\r
70          * INFO is used to pass information about the record translation process.  It does \r
71          * not indicate an error.  It usually will occur when a defaultEncoding value of "BESTGUESS"\r
72          * is passed in.  INFO statements are generated to indicate which character encoding was \r
73          * determined to be the best fit for the data, and why.\r
74          */ \r
75     public final static int INFO = 0;\r
76     \r
77     private List errors;\r
78     private String curRecordID;\r
79     private String curField;\r
80     private String curSubfield;\r
81     private boolean hasMissingID;\r
82     private int maxSeverity;\r
83     \r
84     public class Error {\r
85         protected String curRecordID;\r
86         protected String curField;\r
87         protected String curSubfield;\r
88         protected int severity;\r
89         protected String message;\r
90         \r
91         protected Error(String recordID, String field, String subfield, int severity, String message)\r
92         {\r
93             curRecordID = recordID;\r
94             curField = field;\r
95             curSubfield = subfield;\r
96             this.severity = severity;\r
97             this.message = message;\r
98         }\r
99         \r
100         /**\r
101          *  Formats the error message for display\r
102          *  \r
103          * @return String - a formatted representation of the error.\r
104          */\r
105         public String toString()\r
106         {\r
107             String severityMsg = getSeverityMsg(severity);\r
108             String ret = severityMsg +" : " + message + " --- [ " + curField + " : " + curSubfield  + " ]" ;\r
109             return(ret);\r
110         }\r
111 \r
112         private void setCurRecordID(String curRecordID)\r
113         {\r
114             this.curRecordID = curRecordID;\r
115         }\r
116         \r
117         private String getCurRecordID()\r
118         {\r
119             return(curRecordID);\r
120         }\r
121     }\r
122     \r
123     public ErrorHandler() \r
124     {\r
125         errors = null;\r
126         hasMissingID = false;\r
127         maxSeverity = INFO;\r
128     }\r
129 \r
130     /**\r
131      *  Provides a descriptive string representation of the severity level.\r
132      *  \r
133      * @return String - a descriptive string representation of the severity level\r
134      */\r
135     private String getSeverityMsg(int severity)\r
136     {\r
137         switch (severity) {\r
138             case FATAL:                 return("FATAL       ");\r
139             case MAJOR_ERROR:           return("Major Error ");\r
140             case MINOR_ERROR:           return("Minor Error ");\r
141             case ERROR_TYPO:            return("Typo        ");\r
142             case INFO:                  return("Info        ");\r
143         }\r
144         return(null);\r
145     }\r
146 \r
147     /**\r
148      *  Returns true if any errors (or warnings) were encountered in processing the \r
149      *  current record.  Note that if only INFO level messages are encountered for a \r
150      *  given record, this method will return false.\r
151      *  \r
152      * @return boolean - The highest error severity level encountered for the current record.\r
153      */\r
154     public boolean hasErrors()\r
155     {\r
156         return (errors != null && errors.size() > 0 && maxSeverity > INFO);\r
157     }\r
158     \r
159     /**\r
160      *  Returns the highest error severity level encountered in processing the current record.\r
161      *  \r
162      * @return int - The highest error severity level encountered for the current record.\r
163      */\r
164     public int getMaxSeverity()\r
165     {\r
166         return (maxSeverity);\r
167     }\r
168     \r
169     /**\r
170      *  Returns a list of all of the errors encountered in processing the current record.\r
171      *  \r
172      * @return List - A list of all of the errors encountered for the current record.\r
173      */\r
174     public List getErrors()\r
175     {\r
176         if (errors == null || errors.size() == 0) return null;        \r
177         return(errors);\r
178     }\r
179     \r
180     /**\r
181      *  Resets the list of errors to empty. This should be called at the beginning of \r
182      *  processing of each record.\r
183      */\r
184     public void reset()\r
185     {\r
186         errors = null;\r
187         maxSeverity = INFO;\r
188     }\r
189     \r
190     /**\r
191      *  Logs an error message using the stated severity level.  Uses the values passed  \r
192      *  in id, field, and subfield to note the location of the error.\r
193      * \r
194      * @param id - the record ID of the record currently being processed\r
195      * @param field - the tag of the field currently being processed\r
196      * @param subfield - the subfield tag of the subfield currently being processed\r
197      * @param severity - An indication of the relative severity of the error that was \r
198      *                                          encountered.\r
199      * @param message - A descriptive message about the error that was encountered.\r
200      */\r
201     public void addError(String id, String field, String subfield, int severity, String message)\r
202     {\r
203         if (errors == null) \r
204         {\r
205             errors = new LinkedList();\r
206             hasMissingID = false;\r
207         }\r
208         if (id != null && id.equals("unknown"))  hasMissingID = true;\r
209         else if (hasMissingID)  \r
210         {\r
211             setRecordIDForAll(id);\r
212         }\r
213         errors.add(new Error(id, field, subfield, severity, message));\r
214         if (severity > maxSeverity)   maxSeverity = severity; \r
215     }\r
216     \r
217     /**\r
218      *  Logs an error message using the stated severity level.  Uses the values stored \r
219      *  in curRecordID, curField, and curSubfield to note the location of the error.\r
220      * \r
221      * @param severity - An indication of the relative severity of the error that was \r
222      *                                          encountered.\r
223      * @param message - A descriptive message about the error that was encountered.\r
224      */\r
225     public void addError(int severity, String message)\r
226     {\r
227         addError(curRecordID, curField, curSubfield, severity, message);\r
228     }\r
229 \r
230     private void setRecordIDForAll(String id)\r
231     {\r
232         if (id != null)\r
233         { \r
234             Iterator iter = errors.iterator();       \r
235             while (iter.hasNext())\r
236             {\r
237                 Error err = (Error)(iter.next());\r
238                 if (err.getCurRecordID() == null || err.getCurRecordID().equals("unknown"))\r
239                 {\r
240                     err.setCurRecordID(id);\r
241                 }\r
242             }\r
243             hasMissingID = false;\r
244         }\r
245     }\r
246     \r
247     /**\r
248      *  Sets the record ID to be stored for subsequent error messages that are logged\r
249      *  If any previous messages are stored for the current record that don't have a \r
250      *  stored record ID, set the value for those entries to this value also.\r
251      * \r
252      * @param recordID - the record ID of the record currently being processed\r
253      */\r
254     public void setRecordID(String recordID)\r
255     {\r
256         curRecordID = recordID;\r
257         if (hasMissingID && errors != null) setRecordIDForAll(recordID);\r
258     }\r
259 \r
260     /**\r
261      *  Sets the field tag to be stored for subsequent error messages that are logged\r
262      * \r
263      * @param curField - the tag of the field currently being processed\r
264      */\r
265     public void setCurrentField(String curField)\r
266     {\r
267         this.curField = curField;\r
268     }\r
269     \r
270     /**\r
271      *  Sets the subfield tag to be stored for subsequent error messages that are logged\r
272      * \r
273      * @param curSubfield - the subfield tag of the subfield currently being processed\r
274      */\r
275     public void setCurrentSubfield(String curSubfield)\r
276     {\r
277         this.curSubfield = curSubfield;\r
278     }\r
279 }\r