package org.bifrost.xmlio;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.bifrost.xmlio.config.XmlIOConfig;
import org.bifrost.xmlio.impl.ReaderContentHandler;
import org.xml.sax.SAXException;
/**
* <p>Read data from an XML file into a graph of objects. One or more objects
* get created as a result of parsing an XML file.</p>
* <p>
* Created: Feb 22, 2003<br/>
* Copyright: Copyright (c) 2003<br/>
* Assumptions: none<br/>
* Requires: ReaderContentHandler, XmlException<br/>
* Required by: nothing<br/>
* Revision History:<br/>
* 2003-04-21 Changed to use JAXP instead of Xerces.<br/>
* 2004-04-14 Support for a configuration object<br/>
* </p>
* <p>Example:</p>
* <pre>
* XmlReader reader = new XmlReader("filename.xml", "base.pkg.of.classes");
* SalesLot rootObject = (SalesLot)reader.getRootObject();
*
* Could read a structure like this (where SalesLot is the root Java object
* and the root XML element):
* <SalesLot>
* <Car>
* <make>Saab</make>
* <model>93</model>
* <year>2001</year>
* </Car>
* <Car>
* <make>Saab</make>
* <model>95</model>
* <year>2002</year>
* </Car>
* </SalesLot>
*
* The SalesLot object would implement a method called addCar(Car newCar)
* which would add each of the Car elements to a Collection.
*
* Car would implement setMake(String theMake), setModel(String theModel)
* and setYear(String theYear).
* </pre>
* @author Donald Kittle <donald@bifrost.org> (last commit: $Author: donald $)
* @version 1.0 (revision $Revision: 1.7 $)
* @stereotype Boundary
*/
public class XmlReader
{
private final static String _VERSION =
"$Id: XmlReader.java,v 1.7 2005/02/28 18:17:15 donald Exp $";
private boolean validating = true;
/**
* Exception error messages
*/
public static final String EX_FILE = "Error reading file: ";
public static final String EX_URL = "Error reading url: ";
public static final String EX_PARSING = "Error parsing xml. ";
public static final String EX_NULL_READER = "Reader object is null. ";
/**
* The source of the xml . Is null when reading directly from a stream.
*/
private String source;
/**
* The package where the xml representation objects are to be instantiated
* from.
*/
private String targetPackage;
/**
* The root object read from the xml (represents the root node).
*/
private Object rootObject;
/**
* Framework configuration object.
*/
private XmlIOConfig config = XmlIOConfig.getInstance();
/**
* Constructor. Reads the xml from the file into an object. The target
* objects that reflect the elements of the xml file exist in the package
* specified by the targetPackage parameter.
* @param fileName The path and filename of the xml file
* @param targetPackage The package where the classes representing the xml
* are located
* @throws XmlException when a file or parsing error occurs
*/
public XmlReader(String fileName, String targetPackage) throws XmlException
{
try
{
readXml(new FileInputStream(fileName), targetPackage);
this.source = fileName;
this.targetPackage = targetPackage;
}
catch (IOException ioe)
{
throw new XmlException(EX_FILE + fileName + ", " + ioe.toString());
}
} // end File Constructor()
/**
* Constructor. Reads the xml from the url into an object. The target objects
* that reflect the elements of the xml file exist in the package specified
* by the targetPackage parameter.
* @param url The url for the xml file
* @param targetPackage The package where the classes representing the xml
* are located
* @throws XmlException when a file or parsing error occurs
*/
public XmlReader(URL url, String targetPackage) throws XmlException
{
try
{
readXml(url.openStream(), targetPackage);
this.source = url.toString();
this.targetPackage = targetPackage;
}
catch (IOException ioe)
{
throw new XmlException(EX_URL + source + ", " + ioe.toString());
}
} // end Url Constructor()
/**
* Constructor. Reads the xml input stream into an object. The target
* objects that reflect the elements of the xml file exist in the package
* specified by the targetPackage parameter.
* @param reader The input reader for the xml file
* @param targetPackage The package where the classes representing the xml
* are located
* @throws XmlException when a file or parsing error occurs
*/
public XmlReader(InputStream reader, String targetPackage) throws XmlException
{
if (reader == null)
throw new XmlException(EX_NULL_READER);
readXml(reader, targetPackage);
this.source = null;
this.targetPackage = targetPackage;
} // end Reader Constructor()
/**
* Get the configuration object
* @return the configuration object
*/
public XmlIOConfig getConfig()
{
return config;
}
/**
* Set the configuration object
* @param config the configuration object
*/
public void setConfig(XmlIOConfig config)
{
if (config != null)
this.config = config;
}
/**
* Read the xml from a ReaderContentHandler.
* @param inputStream the source of the xml information
* @param targetPackage the package that the objects representing the xml
* are found in
* @return boolean true if everything went ok, otherwise false
*/
private boolean readXml(InputStream inputStream, String targetPackage)
throws XmlException
{
boolean result = false;
if (inputStream == null)
throw new XmlException(EX_NULL_READER);
if (targetPackage == null)
targetPackage = "";
if (!"".equals(targetPackage) && !targetPackage.endsWith("."))
targetPackage = targetPackage + ".";
rootObject = null;
try
{
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
factory.setNamespaceAware(true);
ReaderContentHandler handler = new ReaderContentHandler(targetPackage);
try
{
SAXParser parser = factory.newSAXParser();
parser.parse(inputStream, handler);
}
catch (ParserConfigurationException pce)
{
try
{
factory.setValidating(false);
factory.setNamespaceAware(false);
SAXParser parser = factory.newSAXParser();
parser.parse(inputStream, handler);
}
catch(Exception e)
{
throw new XmlException(EX_PARSING + e.toString());
}
}
catch (SAXException se)
{
if (se.getException() instanceof XmlException)
throw (XmlException)(se.getException());
throw new XmlException(EX_PARSING + se.toString());
}
catch (IOException ioe) {
throw new XmlException(EX_PARSING + ioe.toString());
}
rootObject = handler.getResult();
handler = null;
result = true;
} // end try to read xml
finally
{
try
{
inputStream.close();
}
catch(IOException ioe) {
}
} // end close reader
return result;
} // end readXml()
/**
* Returns the root object derived from the xml.
* @return Object the the root object derived from the xml or null if the
* xml could not be parsed
*/
public Object getRootObject()
{
return rootObject;
} // end getRootObject()
} // end XmlReader Class