package net.xoetrope.data;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Vector;
import net.xoetrope.debug.DebugLogger;
import net.xoetrope.xml.XmlElement;
import net.xoetrope.xml.XmlParserFactory;
import net.xoetrope.xml.XmlSource;
import net.xoetrope.xml.nanoxml.NanoXmlWriter;
import net.xoetrope.xui.XProject;
import net.xoetrope.xui.build.BuildProperties;
import net.xoetrope.xui.data.XModel;
/**
* <p>Loads a model from a reader</p>
* <p>Copyright (c) Xoetrope Ltd., 1998-2003<br>
* License: see license.txt
* $Revision: 2.11 $
*/
public class XDataSource
{
private static int nextId = 0;
private static boolean useValueAsId = false;
/**
* The current XProject
*/
protected XProject currentProject;
/**
* Create a new data source
* @param project the owner project
*/
public XDataSource( XProject project )
{
currentProject = project;
}
/**
* Read a model from the Reader
* @param r the Reader
*/
public void read( Reader r )
{
XmlElement ele = XmlSource.read( r );
read( ele );
}
/**
* Read an file pointed to by an element in the XML description of the data sources
* @param ele the individual data source description
*/
public void read( XmlElement ele )
{
Vector v = ele.getChildren();
if ( v != null ) {
int numFiles = v.size();
for ( int i = 0; i < numFiles; i++ ) {
try {
XmlElement source = ( XmlElement )v.elementAt( i );
String fileName = source.getAttribute( "filename" );
if ( fileName != null ) {
readDataSource( fileName, source );
}
}
catch ( Exception ex ) {
ex.printStackTrace();
}
}
}
}
/**
* Read the data source file.
* @param fileName the nam eof the file to open
* @param source the XML element describing the source
*/
protected void readDataSource( String fileName, XmlElement source )
{
try {
Reader sr = currentProject.getBufferedReader( fileName, null );
XmlElement src = XmlSource.read( sr );
String type = source.getAttribute( "type" );
if ( ( type == null ) || ( type.length() == 0 ) )
loadTable( src, currentProject.getModel() );
}
catch ( Exception ex ) {
}
}
/**
* Recursively load the model data
* @param source the source element
* @param model the model for the source element
*/
public void loadTable( XmlElement source, XModel model )
{
// Store the node tag name so that the XML can be regenerated/output
model.setTagName( source.getName());
Vector children = source.getChildren();
Enumeration attributes = source.enumerateAttributeNames();
boolean hasAutoId = false;
int numChildren = children.size();
// Count the number of attributes
int numAttributes = 0;
while ( attributes.hasMoreElements() ) {
attributes.nextElement();
numAttributes++;
}
model.setNumAttributes( numAttributes );
// Add the attributes of the source element
attributes = source.enumerateAttributeNames();
while ( attributes.hasMoreElements() ) {
String attribName = ( ( String )attributes.nextElement() );
String valueStr = source.getAttribute( attribName );
model.setAttribValue( model.getAttribute( attribName ), valueStr );
}
if ( useValueAsId && ( source.getAttribute( "value" ) == null ))
model.setAttribValue( model.getAttribute( "value" ), source.getAttribute( "id" ));
// Add the children of the source element
for ( int i = 0; i < numChildren; i++ ) {
XmlElement ele = ( XmlElement )children.elementAt( i );
Object elementName = ele.getAttribute( "id" );
// Give a unique id for unnamed elements
if (( elementName == null ) || ( elementName.toString().length() == 0 )) {
if ( useValueAsId )
elementName = ele.getAttribute( "value" );
else {
elementName = String.valueOf( getNextId() );
hasAutoId = true;
}
}
// Create a node/model for the child
XModel childModel = (XModel)model.get( (String)elementName );
// XModel childModel = ( XModel )model.append( ( String )elementName );
// Allocate store for the child's children
childModel.hasAutoId( hasAutoId );
childModel.setNumChildren( Math.max( childModel.getNumChildren(), ele.getChildren().size() ) );
// Recurse to add the childs details
loadTable( ele, childModel );
}
}
/**
* Get the next ID for anonymous elements
* @return
*/
private int getNextId()
{
return nextId++;
}
/**
* Outputs the datasource as XML
* @param w The Writer of the file.
*/
public void write( Writer w )
{
write( w, currentProject.getModel() );
}
/**
* Outputs the datasource as XML
* @param model the model node to write
* @param w The Writer of the file.
*/
public void write( Writer w, XModel model )
{
try {
outputModel( w, model );
w.flush();
w.close();
}
catch ( IOException ex ) {
ex.printStackTrace();
}
}
/**
* Iterates the XModels and outputs the Elements and their attributes.
* @param w the output writer
* @param model the model to write
*/
public static void outputModel( Writer w, XModel model )
{
try {
XmlElement topEle = XmlParserFactory.getInstance().createXmlElement( model.getTagName() );
outputModel( topEle, model );
//XmlWriter writer = XmlParserFactory.getInstance().getWriter( w );
NanoXmlWriter writer = new NanoXmlWriter( w );
writer.write( topEle, true, 2 );
}
catch ( Exception ex ) {
ex.printStackTrace();
}
}
/**
* Recursive method which builds up the XML Document based on the XModel.
* @param parentEle the current parent element
* @param model the current model being processed
*/
public static void outputModel( XmlElement parentEle, XModel model )
{
for ( int j = 0; j < model.getNumAttributes(); j++ ) {
Object attribValue = model.getAttribValue( j );
String attribName = model.getAttribName( j );
if (( attribValue != null ) && ( attribValue.toString().length() > 0 )) {
String valueStr = attribValue.toString();
if ( !( attribName.compareTo( "name" ) == 0 && model.hasAutoId() ) ) {
parentEle.setAttribute( attribName, valueStr );
}
}
}
for ( int i = 0; i < model.getNumChildren(); i++ ) {
XModel childModel = model.get( i );
XmlElement newEle = parentEle.createElement( childModel.getTagName() );
parentEle.addChild( newEle );
outputModel( newEle, childModel );
}
}
/**
* Iterate the XModels and outputs the Elements and their attributes.
* @param filename the file to write
* @param model the model to write
*/
public void outputModel( String filename, XModel model )
{
if ( BuildProperties.DEBUG )
DebugLogger.trace( "savePath:" + filename );
if ( filename != null ) {
try {
if ( filename.length() > 1 ) {
FileOutputStream fos = new FileOutputStream( filename );
OutputStreamWriter osw = new OutputStreamWriter( fos, "UTF8" );
BufferedWriter bw = new BufferedWriter( osw );
outputModel( bw, currentProject.getModel() );
}
}
catch ( Exception ex ) {
if ( BuildProperties.DEBUG )
DebugLogger.logError( "Could not write content!" );
}
}
}
/**
* Set the model to use the value as the ID for a node if the ID is not specified
* @param state true to use the value when an ID is not specified
*/
public static void setUseValueAsId( boolean state )
{
useValueAsId = state;
}
}