001    /**
002    The contents of this file are subject to the Mozilla Public License Version 1.1 
003    (the "License"); you may not use this file except in compliance with the License. 
004    You may obtain a copy of the License at http://www.mozilla.org/MPL/ 
005    Software distributed under the License is distributed on an "AS IS" basis, 
006    WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the 
007    specific language governing rights and limitations under the License. 
008    
009    The Original Code is "DefaultValidator.java".  Description: 
010    "A default conformance validator." 
011    
012    The Initial Developer of the Original Code is University Health Network. Copyright (C) 
013    2003.  All Rights Reserved. 
014    
015    Contributor(s): ______________________________________. 
016    
017    Alternatively, the contents of this file may be used under the terms of the 
018    GNU General Public License (the  ???GPL???), in which case the provisions of the GPL are 
019    applicable instead of those above.  If you wish to allow use of your version of this 
020    file only under the terms of the GPL and not to allow others to use your version 
021    of this file under the MPL, indicate your decision by deleting  the provisions above 
022    and replace  them with the notice and other provisions required by the GPL License.  
023    If you do not delete the provisions above, a recipient may use your version of 
024    this file under either the MPL or the GPL. 
025    
026    */
027    
028    package ca.uhn.hl7v2.conf.check;
029    
030    import ca.uhn.hl7v2.model.*;
031    import ca.uhn.hl7v2.conf.spec.message.*;
032    import ca.uhn.hl7v2.conf.spec.*;
033    import ca.uhn.hl7v2.util.Terser;
034    import ca.uhn.hl7v2.HL7Exception;
035    import ca.uhn.hl7v2.conf.ProfileException;
036    import ca.uhn.hl7v2.conf.parser.ProfileParser;
037    import ca.uhn.hl7v2.parser.*;
038    import java.util.ArrayList;
039    import java.io.*;
040    import ca.uhn.log.*;
041    import ca.uhn.hl7v2.conf.store.*;
042    
043    /**
044     * A default conformance validator.
045     * @author Bryan Tripp
046     */
047    public class DefaultValidator implements Validator {
048        
049        private EncodingCharacters enc;  //used to check for content in parts of a message
050        private static final HapiLog log = HapiLogFactory.getHapiLog( DefaultValidator.class );
051        
052        /** Creates a new instance of DefaultValidator */
053        public DefaultValidator() {
054            enc = new EncodingCharacters('|', null);  //the | is assumed later -- don't change
055        }
056        
057        /**
058         * @see Validator#validate
059         */
060        public HL7Exception[] validate(Message message, StaticDef profile) throws ProfileException, HL7Exception {
061            ArrayList exList = new ArrayList(20);
062            Terser t = new Terser(message);
063            
064            //check msg type, event type, msg struct ID
065            String msgType = t.get("/MSH-9-1");
066            if (!msgType.equals(profile.getMsgType())) {
067                HL7Exception e =
068                    new ProfileNotFollowedException("Message type " + msgType + " doesn't match profile type of " + profile.getMsgType());
069                exList.add(e);
070            }
071            
072            String evType = t.get("/MSH-9-2");
073            if (!evType.equals(profile.getEventType()) && !profile.getEventType().equalsIgnoreCase("ALL")) {
074                HL7Exception e =
075                    new ProfileNotFollowedException("Event type " + evType + " doesn't match profile type of " + profile.getEventType());
076                exList.add(e);
077            }
078            
079            String msgStruct = t.get("/MSH-9-3");
080            if (msgStruct == null || !msgStruct.equals(profile.getMsgStructID())) {
081                HL7Exception e =
082                    new ProfileNotFollowedException("Message structure " + msgStruct + " doesn't match profile type of " + profile.getMsgStructID());
083                exList.add(e);
084            }
085            
086            Exception[] childExceptions; 
087            childExceptions = testGroup(message, profile, profile.getIdentifier());
088            for (int i = 0; i < childExceptions.length; i++) {
089                exList.add(childExceptions[i]);
090            }
091            
092            return toArray(exList);
093        }
094        
095        /**
096         * Tests a group against a group section of a profile.
097         */
098        public HL7Exception[] testGroup(Group group, AbstractSegmentContainer profile, String profileID) throws ProfileException {
099            ArrayList exList = new ArrayList(20);
100            ArrayList allowedStructures = new ArrayList(20);
101            
102            for (int i = 1; i <= profile.getChildren(); i++) {
103                ProfileStructure struct = profile.getChild(i);
104                
105                //only test a structure in detail if it isn't X
106                if (!struct.getUsage().equalsIgnoreCase("X")) {
107                    allowedStructures.add(struct.getName());
108                    
109                    //see which instances have content
110                    try {
111                        Structure[] instances = group.getAll(struct.getName());
112                        ArrayList instancesWithContent = new ArrayList(10);
113                        for (int j = 0; j < instances.length; j++) {
114                            if (hasContent(instances[j])) instancesWithContent.add(instances[j]);
115                        }
116                        
117                        HL7Exception ce = testCardinality(instancesWithContent.size(),
118                        struct.getMin(), struct.getMax(), struct.getUsage(), struct.getName());
119                        if (ce != null) exList.add(ce);
120                        
121                        //test children on instances with content
122                        for (int j = 0; j < instancesWithContent.size(); j++) {
123                            Structure s = (Structure) instancesWithContent.get(j);
124                            HL7Exception[] childExceptions = testStructure(s, struct, profileID);
125                            addToList(childExceptions, exList);
126                        }
127                    } catch (HL7Exception he) {
128                        exList.add(new ProfileNotHL7CompliantException(struct.getName() + " not found in message"));
129                    }
130                }
131            }
132         
133            //complain about X structures that have content
134            addToList(checkForExtraStructures(group, allowedStructures), exList);
135            
136            return toArray(exList);
137        }
138        
139        /**
140         * Checks a group's children against a list of allowed structures for the group 
141         * (ie those mentioned in the profile with usage other than X).  Returns 
142         * a list of exceptions representing structures that appear in the message  
143         * but are not supposed to.  
144         */
145        private HL7Exception[] checkForExtraStructures(Group group, ArrayList allowedStructures) throws ProfileException {
146            ArrayList exList = new ArrayList();
147            String[] childNames = group.getNames();
148            for (int i = 0; i < childNames.length; i++) {
149                if (!allowedStructures.contains(childNames[i])) {
150                    try {
151                        Structure[] reps = group.getAll(childNames[i]);
152                        for (int j = 0; j < reps.length; j++) {
153                            if (hasContent(reps[j])) {
154                                HL7Exception e =
155                                    new XElementPresentException("The structure " 
156                                        + childNames[i] 
157                                        + " appears in the message but not in the profile");
158                                exList.add(e);
159                            }
160                        }
161                    } catch (HL7Exception he) {
162                        throw new ProfileException("Problem checking profile", he);
163                    }
164                }
165            }
166            return toArray(exList);
167        }
168        
169        /**
170         * Checks cardinality and creates an appropriate exception if out 
171         * of bounds.  The usage code is needed because if min cardinality
172         * is > 0, the min # of reps is only required if the usage code
173         * is 'R' (see HL7 v2.5 section 2.12.6.4).  
174         * @param reps the number of reps
175         * @param min the minimum number of reps
176         * @param max the maximum number of reps (-1 means *)
177         * @param usage the usage code 
178         * @param name the name of the repeating structure (used in exception msg)
179         * @return null if cardinality OK, exception otherwise
180         */
181        protected HL7Exception testCardinality(int reps, int min, int max, String usage, String name) {
182            HL7Exception e = null;
183            if (reps < min && usage.equalsIgnoreCase("R")) {
184                e = new ProfileNotFollowedException(name + " must have at least " + min + " repetitions (has " + reps + ")");
185            } else if (max > 0 && reps > max) {
186                e = new ProfileNotFollowedException(name + " must have no more than " + max + " repetitions (has " + reps + ")");
187            }
188            return e;
189        }
190        
191        /**
192         * Tests a structure (segment or group) against the corresponding part of a profile.  
193         */
194        public HL7Exception[] testStructure(Structure s, ProfileStructure profile, String profileID) throws ProfileException {
195            ArrayList exList = new ArrayList(20);
196            if (profile instanceof Seg) {
197                if (Segment.class.isAssignableFrom(s.getClass())) {
198                    addToList(testSegment((Segment) s, (Seg) profile, profileID), exList);
199                } else {
200                    exList.add(new ProfileNotHL7CompliantException("Mismatch between a segment in the profile and the structure " 
201                            + s.getClass().getName() + " in the message"));
202                }
203            } else if (profile instanceof SegGroup) {
204                if (Group.class.isAssignableFrom(s.getClass())) {
205                    addToList(testGroup((Group) s, (SegGroup) profile, profileID), exList);
206                } else {
207                    exList.add(new ProfileNotHL7CompliantException("Mismatch between a group in the profile and the structure " 
208                            + s.getClass().getName() + " in the message"));
209                }
210            }
211            return toArray(exList);
212        }
213        
214        /**
215         * Tests a segment against a segment section of a profile.
216         */
217        public HL7Exception[] testSegment(ca.uhn.hl7v2.model.Segment segment, Seg profile, String profileID) throws ProfileException {
218            ArrayList exList = new ArrayList(20);
219            ArrayList allowedFields = new ArrayList(20);
220            
221            for (int i = 1; i <= profile.getFields(); i++) {
222                Field field = profile.getField(i);
223                
224                //only test a field in detail if it isn't X
225                if (!field.getUsage().equalsIgnoreCase("X")) {
226                    allowedFields.add(new Integer(i));
227                    
228                    //see which instances have content
229                    try {
230                        Type[] instances = segment.getField(i);
231                        ArrayList instancesWithContent = new ArrayList(10);
232                        for (int j = 0; j < instances.length; j++) {
233                            if (hasContent(instances[j])) instancesWithContent.add(instances[j]);
234                        }
235                        
236                        HL7Exception ce = testCardinality(instancesWithContent.size(),
237                        field.getMin(), field.getMax(), field.getUsage(), field.getName());
238                        if (ce != null) {
239                            ce.setFieldPosition(i);
240                            exList.add(ce);
241                        }
242                        
243                        //test field instances with content
244                        for (int j = 0; j < instancesWithContent.size(); j++) {
245                            Type s = (Type) instancesWithContent.get(j);
246                            
247                            boolean escape = true; //escape field value when checking length
248                            if (profile.getName().equalsIgnoreCase("MSH") && i < 3) {
249                                escape = false;
250                            }
251                            HL7Exception[] childExceptions = testField(s, field, escape, profileID);
252                            for (int k = 0; k < childExceptions.length; k++) {
253                                childExceptions[k].setFieldPosition(i);
254                            }
255                            addToList(childExceptions, exList);
256                        }
257                    } catch (HL7Exception he) {
258                        exList.add(new ProfileNotHL7CompliantException("Field " + i + " not found in message"));
259                    }
260                }
261                
262            }
263            
264            //complain about X fields with content
265            this.addToList(checkForExtraFields(segment, allowedFields), exList);
266            
267            HL7Exception[] ret = toArray(exList);        
268            for (int i = 0; i < ret.length; i++) {
269                ret[i].setSegmentName(profile.getName());
270            }
271            return ret;
272        }
273        
274        /**
275         * Checks a segment against a list of allowed fields 
276         * (ie those mentioned in the profile with usage other than X).  Returns 
277         * a list of exceptions representing field that appear 
278         * but are not supposed to.  
279         * @param allowedFields an array of Integers containing field #s of allowed fields
280         */
281        private HL7Exception[] checkForExtraFields(Segment segment, ArrayList allowedFields) throws ProfileException {
282            ArrayList exList = new ArrayList();
283            for (int i = 1; i <= segment.numFields(); i++) {
284                if (!allowedFields.contains(new Integer(i))) {
285                    try {
286                        Type[] reps = segment.getField(i);
287                        for (int j = 0; j < reps.length; j++) {
288                            if (hasContent(reps[j])) {
289                                HL7Exception e =  new XElementPresentException(
290                                    "Field " + i + " in " + segment.getName() + " appears in the message but not in the profile");
291                                exList.add(e);
292                            }
293                        }
294                    } catch (HL7Exception he) {
295                        throw new ProfileException("Problem testing against profile", he);
296                    }
297                }
298            }     
299            return this.toArray(exList);
300        }
301        
302        /**
303         * Tests a Type against the corresponding section of a profile.
304         * @param encoded optional encoded form of type (if you want to specify this -- if null,  
305         *      default pipe-encoded form is used to check length and constant val)
306         */
307        public HL7Exception[] testType(Type type, AbstractComponent profile, String encoded, String profileID) {
308            ArrayList exList = new ArrayList();
309            if (encoded == null) encoded = PipeParser.encode(type, this.enc);
310    
311            HL7Exception ue = testUsage(encoded, profile.getUsage(), profile.getName());
312            if (ue != null) exList.add(ue);
313    
314            if ( !profile.getUsage().equals("X") ) {
315                //check datatype
316                String typeClass = type.getClass().getName();
317                if (typeClass.indexOf("." + profile.getDatatype()) < 0) {
318                    typeClass = typeClass.substring(typeClass.lastIndexOf('.') + 1);
319                    exList.add(new ProfileNotHL7CompliantException("HL7 datatype " + typeClass + " doesn't match profile datatype " + profile.getDatatype()));
320                }
321                
322                //check length
323                if (encoded.length() > profile.getLength())
324                    exList.add(new ProfileNotFollowedException("The type " + profile.getName() + " has length " + encoded.length() + " which exceeds max of " + profile.getLength()));
325                
326                //check constant value
327                if (profile.getConstantValue() != null && profile.getConstantValue().length() > 0) {
328                    if (!encoded.equals(profile.getConstantValue()))
329                        exList.add(new ProfileNotFollowedException("'" + encoded + "' doesn't equal constant value of '" + profile.getConstantValue() + "'"));
330                }
331                
332                HL7Exception[] te = testTypeAgainstTable(type, profile, profileID);
333                for (int i = 0; i < te.length; i++) {
334                    exList.add(te[i]);
335                }
336            }
337        
338            return this.toArray(exList);
339        }
340        
341        /**
342         * Tests whether the given type falls within a maximum length.  
343         * @return null of OK, an HL7Exception otherwise 
344         */
345        public HL7Exception testLength(Type type, int maxLength) {
346            HL7Exception e = null;
347            String encoded = PipeParser.encode(type, this.enc);
348            if (encoded.length() > maxLength) {
349                e = new ProfileNotFollowedException("Length of " + encoded.length() + " exceeds maximum of " + maxLength);
350            }
351            return e;
352        }
353        
354        /**
355         * Tests an element against the corresponding usage code.  The element 
356         * is required in its encoded form.  
357         * @param encoded the pipe-encoded message element 
358         * @param usage the usage code (e.g. "CE")
359         * @param name the name of the element (for use in exception messages)
360         * @returns null if there is no problem, an HL7Exception otherwise 
361         */
362        private HL7Exception testUsage(String encoded, String usage, String name) {
363            HL7Exception e = null;
364            if (usage.equalsIgnoreCase("R")) {
365                if (encoded.length() == 0) 
366                    e = new ProfileNotFollowedException("Required element " + name + " is missing");
367            } else if (usage.equalsIgnoreCase("RE")) {
368                //can't test anything 
369            } else if (usage.equalsIgnoreCase("O")) {
370                //can't test anything
371            } else if (usage.equalsIgnoreCase("C")) {
372                //can't test anything yet -- wait for condition syntax in v2.6 
373            } else if (usage.equalsIgnoreCase("CE")) {
374                //can't test anything
375            } else if (usage.equalsIgnoreCase("X")) {
376                if (encoded.length() > 0) 
377                    e = new XElementPresentException("Element " + name + " is present but specified as not used (X)");
378            } else if (usage.equalsIgnoreCase("B")) {
379                //can't test anything 
380            }                
381            return e;
382        }
383        
384        /**
385         * Tests table values for ID, IS, and CE types.  An empty list is returned for 
386         * all other types or if the table name or number is missing.  
387         */
388        private HL7Exception[] testTypeAgainstTable(Type type, AbstractComponent profile, String profileID) {
389            ArrayList exList = new ArrayList();
390            if (profile.getTable() != null && (type.getName().equals("IS") || type.getName().equals("ID"))) {
391                String codeSystem = makeTableName(profile.getTable());
392                String value = ((Primitive) type).getValue();
393                addTableTestResult(exList, profileID, codeSystem, value);
394            } else if (type.getName().equals("CE")) {
395                String value = Terser.getPrimitive(type, 1, 1).getValue();
396                String codeSystem = Terser.getPrimitive(type, 3, 1).getValue();
397                addTableTestResult(exList, profileID, codeSystem, value);
398    
399                value = Terser.getPrimitive(type, 4, 1).getValue();
400                codeSystem = Terser.getPrimitive(type, 6, 1).getValue();
401                addTableTestResult(exList, profileID, codeSystem, value);
402            }
403            return this.toArray(exList);
404        }
405        
406        private void addTableTestResult(ArrayList exList, String profileID, String codeSystem, String value) {
407            if (codeSystem != null && value != null) {
408                HL7Exception e = testValueAgainstTable(profileID, codeSystem, value);
409                if (e != null) exList.add(e);
410            }        
411        }
412        
413        private HL7Exception testValueAgainstTable(String profileID, String codeSystem, String value) {
414            HL7Exception ret = null;
415            CodeStore store = ProfileStoreFactory.getCodeStore(profileID, codeSystem);
416            if (store == null) {
417                log.warn("Not checking value " + value + ": no code store was found for profile " + profileID 
418                    + " code system " + codeSystem);
419            } else {
420                if (!store.isValidCode(codeSystem, value))
421                    ret = new ProfileNotFollowedException("Code " + value + " not found in table " + codeSystem + ", profile " + profileID);
422            }
423            return ret;
424        }
425        
426        private String makeTableName(String hl7Table) {
427            StringBuffer buf = new StringBuffer("HL7");
428            if (hl7Table.length() < 4) buf.append("0");
429            if (hl7Table.length() < 3) buf.append("0");
430            if (hl7Table.length() < 2) buf.append("0");
431            buf.append(hl7Table);
432            return buf.toString();
433        }
434        
435        public HL7Exception[] testField(Type type, Field profile, boolean escape, String profileID) throws ProfileException {
436            ArrayList exList = new ArrayList(20);
437            
438            //account for MSH 1 & 2 which aren't escaped
439            String encoded = null;
440            if (!escape && Primitive.class.isAssignableFrom(type.getClass())) encoded = ((Primitive) type).getValue();
441            
442            addToList(testType(type, profile, encoded, profileID), exList);
443            
444            //test children
445            if (profile.getComponents() > 0 && !profile.getUsage().equals("X")) {
446                if (Composite.class.isAssignableFrom(type.getClass())) {
447                    Composite comp = (Composite) type;
448                    for (int i = 1; i <= profile.getComponents(); i++) {
449                        Component childProfile = profile.getComponent(i);
450                        try {
451                            Type child = comp.getComponent(i-1);
452                            addToList(testComponent(child, childProfile, profileID), exList);
453                        } catch (DataTypeException de) {
454                            exList.add(new ProfileNotHL7CompliantException("More components in profile than allowed in message: " + de.getMessage()));
455                        }
456                    }
457                    addToList(checkExtraComponents(comp, profile.getComponents()), exList);
458                } else {
459                    exList.add(new ProfileNotHL7CompliantException(
460                    "A field has type primitive " + type.getClass().getName() + " but the profile defines components"));
461                }
462            }
463            
464            return toArray(exList);
465        }
466        
467        public HL7Exception[] testComponent(Type type, Component profile, String profileID) throws ProfileException {
468            ArrayList exList = new ArrayList(20);
469            
470            addToList(testType(type, profile, null, profileID), exList);
471            
472            //test children
473            if (profile.getSubComponents() > 0 && !profile.getUsage().equals("X") && hasContent(type)) {
474                if (Composite.class.isAssignableFrom(type.getClass())) {
475                    Composite comp = (Composite) type;
476                    for (int i = 1; i <= profile.getSubComponents(); i++) {
477                        SubComponent childProfile = profile.getSubComponent(i);
478                        try {
479                            Type child = comp.getComponent(i-1);
480                            addToList(testType(child, childProfile, null, profileID), exList);
481                        } catch (DataTypeException de) {
482                            exList.add(new ProfileNotHL7CompliantException("More subcomponents in profile than allowed in message: " + de.getMessage()));
483                        }
484                    }
485                    addToList(checkExtraComponents(comp, profile.getSubComponents()), exList);
486                } else {
487                    exList.add(new ProfileNotFollowedException(
488                    "A component has primitive type " + type.getClass().getName() + " but the profile defines subcomponents"));
489                }
490            }
491            
492            return toArray(exList);
493        }
494        
495        /** Tests for extra components (ie any not defined in the profile) */
496        private HL7Exception[] checkExtraComponents(Composite comp, int numInProfile) throws ProfileException {
497            ArrayList exList = new ArrayList(20);
498            
499            StringBuffer extra = new StringBuffer();
500            for (int i = numInProfile; i < comp.getComponents().length; i++) {
501                try {
502                    String s = PipeParser.encode(comp.getComponent(i), enc);
503                    if (s.length() > 0) {
504                        extra.append(s);
505                        extra.append(enc.getComponentSeparator());
506                    }
507                } catch (DataTypeException de) {
508                    throw new ProfileException("Problem testing against profile", de);
509                }
510            }
511            
512            if (extra.toString().length() > 0) {
513                exList.add(new XElementPresentException("The following components are not defined in the profile: " + extra.toString()));
514            }
515            
516            return toArray(exList);
517        }
518        
519        /**
520         * Tests a composite against the corresponding section of a profile.
521         */
522        /*public HL7Exception[] testComposite(Composite comp, AbstractComposite profile) {
523        }*/
524        
525        /**
526         * Tests a primitive datatype against a profile.  Tests include
527         * length, datatype, whether the profile defines any children
528         * (this would indicate an error), constant value if defined.
529         * Table values are not verified.
530         */
531        /*public Hl7Exception[] testPrimitive(Primitive, AbstractComponent profile) {
532         
533        }*/
534        
535        /** Returns true is there is content in the given structure */
536        private boolean hasContent(Structure struct) throws HL7Exception {
537            if (Group.class.isAssignableFrom(struct.getClass())) {
538                return hasContent( (Group) struct );
539            } else if (Segment.class.isAssignableFrom(struct.getClass())) {
540                return hasContent( (Segment) struct );
541            } else {
542                throw new HL7Exception("Structure " + struct.getClass().getName() + " not recognized", HL7Exception.APPLICATION_INTERNAL_ERROR);
543            }
544        }
545        
546        /** Returns true is there is content in the given group */
547        private boolean hasContent(Group group) throws HL7Exception {
548            boolean has = false;
549            String encoded = PipeParser.encode(group, enc);
550            if (encoded.indexOf('|') >= 0) has = true;
551            return has;
552        }
553        
554        /** Returns true is there is content in the given segment */
555        private boolean hasContent(Segment segment) {
556            boolean has = false;
557            String encoded = PipeParser.encode(segment, enc);
558            if (encoded != null && encoded.length() > 3) has = true;
559            return has;
560        }
561        
562        /** Returns true is there is content in the given type */
563        private boolean hasContent(Type type) {
564            boolean has = false;
565            String encoded = PipeParser.encode(type, enc);
566            if (encoded != null && encoded.length() > 0) has = true;
567            return has;
568        }
569        
570        /** Appends an array of HL7 exceptions to a list */
571        private void addToList(HL7Exception[] exceptions, ArrayList list) {
572            for (int i = 0; i < exceptions.length; i++) {
573                list.add(exceptions[i]);
574            }
575        }
576        
577        /** Returns the HL7 exceptions in the given arraylist in an array */
578        private HL7Exception[] toArray(ArrayList list) {
579            return (HL7Exception[]) list.toArray(new HL7Exception[0]);
580        }
581        
582        public static void main(String args[]) {
583            
584            if (args.length != 2) {
585                System.out.println("Usage: DefaultValidator message_file profile_file");
586                System.exit(1);
587            }
588            
589            DefaultValidator val = new DefaultValidator();
590            try {
591                String msgString = loadFile(args[0]);
592                Parser parser = new GenericParser();
593                Message message = parser.parse(msgString);
594                
595                String profileString = loadFile(args[1]);
596                ProfileParser profParser = new ProfileParser(true);
597                RuntimeProfile profile = profParser.parse(profileString);
598                
599                HL7Exception[] exceptions = val.validate(message, profile.getMessage());
600                
601                System.out.println("Exceptions: "); 
602                for (int i = 0; i < exceptions.length; i++) {
603                    System.out.println((i + 1) + ". " + exceptions[i].getMessage());
604                }
605            } catch (Exception e) {
606                e.printStackTrace();
607            }
608        }
609        
610        /** loads file at the given path */
611        private static String loadFile(String path) throws IOException {
612            File file = new File(path);
613            //char[] cbuf = new char[(int) file.length()];
614            BufferedReader in = new BufferedReader(new FileReader(file));
615            StringBuffer buf = new StringBuffer(5000);
616            int c = -1;
617            while ( (c = in.read()) != -1) {
618                buf.append( (char) c );
619            }
620            //in.read(cbuf, 0, (int) file.length());
621            in.close();
622            //return String.valueOf(cbuf);
623            return buf.toString();
624        }
625        
626    }