
gov.aps.jca.configuration.SAXConfigurationHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jca Show documentation
Show all versions of jca Show documentation
JCA is an EPICS Channel Access library for Java. For more information concerning EPICS or Channel Access please refer to the <a href="http://www.aps.anl.gov/epics">EPICS Web pages</a> or read the <a href="http://www.aps.anl.gov/epics/base/R3-14/8-docs/CAref.html">Channel Access manual (3.14)</a>.
<p>This module also includes CAJ, A 100% pure Java implementation of the EPICS Channel Access library.</p>
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package gov.aps.jca.configuration;
import java.util.ArrayList;
import java.util.BitSet;
import org.xml.sax.Attributes;
import org.xml.sax.ErrorHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
/**
* A SAXConfigurationHandler helps build Configurations out of sax events.
*
* @author Federico Barbieri
* @author Peter Donald
*/
public class SAXConfigurationHandler
extends DefaultHandler
implements ErrorHandler
{
/**
* Likely number of nested configuration items. If more is
* encountered the lists will grow automatically.
*/
private static final int EXPECTED_DEPTH = 5;
private final ArrayList m_elements = new ArrayList( EXPECTED_DEPTH );
private final ArrayList m_values = new ArrayList( EXPECTED_DEPTH );
/**
* Contains true at index n if space in the configuration with
* depth n is to be preserved.
*/
private final BitSet m_preserveSpace = new BitSet();
private Configuration m_configuration;
private Locator m_locator;
/**
* Get the configuration object that was built.
*
* @return a Configuration
object
*/
public Configuration getConfiguration()
{
return m_configuration;
}
/**
* Clears all data from this configuration handler.
*/
public void clear()
{
m_elements.clear();
m_values.clear();
m_locator = null;
}
/**
* Set the document Locator
to use.
*
* @param locator a Locator
value
*/
public void setDocumentLocator( final Locator locator )
{
m_locator = locator;
}
/**
* Handling hook for character data.
*
* @param ch a char[]
of data
* @param start offset in the character array from which to start reading
* @param end length of character data
* @throws SAXException if an error occurs
*/
public void characters( final char[] ch, int start, int end )
throws SAXException
{
// it is possible to play micro-optimization here by doing
// manual trimming and thus preserve some precious bits
// of memory, but it's really not important enough to justify
// resulting code complexity
final int depth = m_values.size() - 1;
final StringBuffer valueBuffer = (StringBuffer)m_values.get( depth );
valueBuffer.append( ch, start, end );
}
/**
* Handling hook for finishing parsing of an element.
*
* @param namespaceURI a String
value
* @param localName a String
value
* @param rawName a String
value
* @throws SAXException if an error occurs
*/
public void endElement( final String namespaceURI,
final String localName,
final String rawName )
throws SAXException
{
final int depth = m_elements.size() - 1;
final DefaultConfiguration finishedConfiguration =
(DefaultConfiguration)m_elements.remove( depth );
final String accumulatedValue =
( (StringBuffer)m_values.remove( depth ) ).toString();
if( finishedConfiguration.getChildren().length == 0 )
{
// leaf node
String finishedValue;
if( m_preserveSpace.get( depth ) )
{
finishedValue = accumulatedValue;
}
else if( 0 == accumulatedValue.length() )
{
finishedValue = null;
}
else
{
finishedValue = accumulatedValue.trim();
}
finishedConfiguration.setValue( finishedValue );
}
else
{
final String trimmedValue = accumulatedValue.trim();
if( trimmedValue.length() > 0 )
{
throw new SAXException( "Not allowed to define mixed content in the " +
"element " + finishedConfiguration.getName() + " at " +
finishedConfiguration.getLocation() );
}
}
if( 0 == depth )
{
m_configuration = finishedConfiguration;
}
}
/**
* Create a new DefaultConfiguration
with the specified
* local name and location.
*
* @param localName a String
value
* @param location a String
value
* @return a DefaultConfiguration
value
*/
protected DefaultConfiguration createConfiguration( final String localName,
final String location )
{
return new DefaultConfiguration( localName, location );
}
/**
* Handling hook for starting parsing of an element.
*
* @param namespaceURI a String
value
* @param localName a String
value
* @param rawName a String
value
* @param attributes an Attributes
value
* @throws SAXException if an error occurs
*/
public void startElement( final String namespaceURI,
final String localName,
final String rawName,
final Attributes attributes )
throws SAXException
{
final DefaultConfiguration configuration =
createConfiguration( rawName, getLocationString() );
// depth of new configuration (not decrementing here, configuration
// is to be added)
final int depth = m_elements.size();
boolean preserveSpace = false; // top level element trims space by default
if( depth > 0 )
{
final DefaultConfiguration parent =
(DefaultConfiguration)m_elements.get( depth - 1 );
parent.addChild( configuration );
// inherits parent's space preservation policy
preserveSpace = m_preserveSpace.get( depth - 1 );
}
m_elements.add( configuration );
m_values.add( new StringBuffer() );
final int attributesSize = attributes.getLength();
for( int i = 0; i < attributesSize; i++ )
{
final String name = attributes.getQName( i );
final String value = attributes.getValue( i );
if( !name.equals( "xml:space" ) )
{
configuration.setAttribute( name, value );
}
else
{
preserveSpace = value.equals( "preserve" );
}
}
if( preserveSpace )
{
m_preserveSpace.set( depth );
}
else
{
m_preserveSpace.clear( depth );
}
}
/**
* This just throws an exception on a parse error.
* @param exception the parse error
* @throws SAXException if an error occurs
*/
public void error( final SAXParseException exception )
throws SAXException
{
throw exception;
}
/**
* This just throws an exception on a parse error.
* @param exception the parse error
* @throws SAXException if an error occurs
*/
public void warning( final SAXParseException exception )
throws SAXException
{
throw exception;
}
/**
* This just throws an exception on a parse error.
* @param exception the parse error
* @throws SAXException if an error occurs
*/
public void fatalError( final SAXParseException exception )
throws SAXException
{
throw exception;
}
/**
* Returns a string showing the current system ID, line number and column number.
*
* @return a String
value
*/
protected String getLocationString()
{
if( null == m_locator )
{
return "Unknown";
}
else
{
return
m_locator.getSystemId() + ":" +
m_locator.getLineNumber() + ":" +
m_locator.getColumnNumber();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy