package org.apache.torque.generator.configuration.source;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import static org.apache.torque.generator.configuration.source.SourceConfigurationTags.ELEMENTS_ATTRIBUTE;
import static org.apache.torque.generator.configuration.source.SourceConfigurationTags.TRANSFORMER_CLASS_ATTRIBUTE;
import static org.apache.torque.generator.configuration.source.SourceConfigurationTags.TRANSFORMER_TAG;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.torque.generator.configuration.ConfigurationProvider;
import org.apache.torque.generator.configuration.paths.ProjectPaths;
import org.apache.torque.generator.source.transform.SourceTransformer;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* Reads a source transformer from the controller configuration file.
*/
public class SourceTransformerSaxHandler extends DefaultHandler
{
/** The logger for this class. */
private static Log log = LogFactory.getLog(DefaultHandler.class);
/** The SourceTransformer which is currently configured. */
private SourceTransformer sourceTransformer;
/** On which Elements the sourceTransformer should be applied. */
private String elements;
/** The current nesting level inside the processed element. */
private int level = 0;
/**
* The name of the currently read bean property of the transformer,
* or null if no property is currently read.
*/
private String propertyName;
/**
* The value of the currently read bean property of the transformer,
* or null if no property is currently read or the property is a
* list property.
*/
private StringBuilder simplePropertyValue;
/**
* The value of the currently read bean property of the transformer,
* or null if no property is currently read or the property is a
* simple property.
*/
private ArrayList<String> listPropertyValue;
/**
* The value of the currently read list entry of the currently read
* property of the transformer,
* or null if no list entry is currently read or the property is a
* simple property.
*/
private StringBuilder listPropertyEntry;
/**
* Constructor.
*
* @param configurationProvider The access object for the configuration
* files, not null.
* @param projectPaths The paths of the surrounding project, not null.
*
* @throws NullPointerException if an argument is null.
*/
public SourceTransformerSaxHandler(
ConfigurationProvider configurationProvider,
ProjectPaths projectPaths)
{
if (configurationProvider == null)
{
throw new NullPointerException("configurationProvider must not be null");
}
if (projectPaths == null)
{
throw new NullPointerException("projectPaths must not be null");
}
}
/**
* {@inheritDoc}
*/
@Override
public void startElement(String uri, String localName, String rawName,
Attributes attributes)
throws SAXException
{
if (level == 0)
{
level++;
if (rawName.equals(TRANSFORMER_TAG))
{
String className = attributes.getValue(
TRANSFORMER_CLASS_ATTRIBUTE);
if (className == null)
{
throw new SAXException(
"The attribute " + TRANSFORMER_CLASS_ATTRIBUTE
+ " must not be null for the element "
+ TRANSFORMER_TAG);
}
elements = attributes.getValue(ELEMENTS_ATTRIBUTE);
sourceTransformer = createJavaSourceTransformer(className);
}
else
{
throw new SAXException("Unknown element " + rawName);
}
}
else if (level == 1)
{
level++;
propertyName = rawName;
simplePropertyValue = new StringBuilder();
}
else if (level == 2)
{
level++;
if (simplePropertyValue.length() > 0
&& !StringUtils.isWhitespace(simplePropertyValue.toString()))
{
throw new SAXException(
"Cannot parse both text content and child elements "
+ " in element " + propertyName);
}
simplePropertyValue = null;
if (listPropertyValue == null)
{
listPropertyValue = new ArrayList<String>();
}
listPropertyEntry = new StringBuilder();
}
else
{
throw new SAXException("unknown Element " + rawName);
}
}
/**
* {@inheritDoc}
*/
@Override
public void endElement(String uri, String localName, String rawName)
throws SAXException
{
level--;
if (level == 2)
{
listPropertyValue.add(listPropertyEntry.toString());
listPropertyEntry = null;
}
else if (level == 1)
{
if (!PropertyUtils.isWriteable(sourceTransformer, propertyName))
{
throw new SAXException("No setter found for property "
+ propertyName
+ " in class "
+ sourceTransformer.getClass().getName());
}
Object propertyValue;
if (simplePropertyValue != null)
{
propertyValue = simplePropertyValue.toString();
}
else
{
propertyValue = listPropertyValue;
}
try
{
BeanUtils.copyProperty(
sourceTransformer,
propertyName,
propertyValue);
}
catch (InvocationTargetException e)
{
throw new SAXException("error while setting Property "
+ propertyName
+ " for java transformer "
+ sourceTransformer.getClass().getName()
+ " with value "
+ propertyValue.toString(),
e);
}
catch (IllegalAccessException e)
{
throw new SAXException("error while setting Property "
+ propertyName
+ " for java transformer "
+ sourceTransformer.getClass().getName()
+ " with value "
+ propertyValue.toString(),
e);
}
propertyName = null;
propertyValue = null;
}
else if (level != 0)
{
throw new SAXException("endElemend reached Level " + level);
}
}
/**
* {@inheritDoc}
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException
{
if (simplePropertyValue != null)
{
for (int i = start; i < start + length; ++i)
{
simplePropertyValue.append(ch[i]);
}
return;
}
if (listPropertyEntry != null)
{
for (int i = start; i < start + length; ++i)
{
listPropertyEntry.append(ch[i]);
}
return;
}
}
/**
* Returns the configuration filled with the contents of the parsed snippet.
*
* @return the configuration which was filled, not null if a
* matching snippet was processed.
*/
public SourceTransformer getSourceTransformer()
{
return sourceTransformer;
}
/**
* Returns the path to source elements to which the transformer is applied.
*
* @return the path to the source element, or null to apply the transformer
* to the root element.
*/
public String getElements()
{
return elements;
}
/**
* Returns the configuration filled with the contents of the parsed snippet.
*
* @return the configuration which was filled, not null if a
* matching snippet was processed.
*/
public boolean isFinished()
{
return (sourceTransformer != null && level == 0);
}
/**
* Creates an instance of a transformer.
*
* @param className the name of the transformer to be created.
*
* @return the instance of the transformer, not null.
*
* @throws ExceptionInInitializerError if an error occurs in the
* initializer of the transformer.
* @throws LinkageError if the linkage fails.
* @throws SAXException if any other error occurs during instantiation
* of the class.
*/
private static SourceTransformer createJavaSourceTransformer(
String className)
throws SAXException
{
Class<?> transformerClass;
try
{
transformerClass = Class.forName(className);
}
catch (ClassNotFoundException e)
{
throw new SAXException(
"Error while initializing a source transformer :"
+ " Could not load class " + className, e);
}
catch (ExceptionInInitializerError e)
{
log.error(
"Error while initializing a source transformer :"
+ " Could not initialize class " + className
+ " : " + e.getMessage());
throw e;
}
catch (LinkageError e)
{
log.error(
"Error while initializing a source transformer :"
+ " Could not link class " + className
+ " : " + e.getMessage());
throw e;
}
SourceTransformer result;
try
{
Constructor<?> constructor
= transformerClass.getConstructor();
result = (SourceTransformer) constructor.newInstance();
}
catch (NoSuchMethodException e)
{
throw new SAXException(
"Error while instantiating a source transformer :"
+ " The class " + className
+ " has no default constructor",
e);
}
catch (ClassCastException e)
{
throw new SAXException(
"Error while instantiating a source transformer :"
+ " The class " + className
+ " is not an instance of "
+ SourceTransformer.class.getName(),
e);
}
catch (IllegalAccessException e)
{
throw new SAXException(
"Error while instantiating a source transformer :"
+ " The constructor of class "
+ className + " could not be accessed",
e);
}
catch (InvocationTargetException e)
{
throw new SAXException(
"Error while instantiating a source transformer :"
+ " The constructor of class "
+ className + " could not be called",
e);
}
catch (InstantiationException e)
{
throw new SAXException(
"Error while instantiating a source transformer :"
+ " The class " + className
+ " represents an abstract class, "
+ "an interface, an array class, a primitive type, "
+ "or void, or the class has no parameterless constructor, "
+ "or the instantiation fails for some other reason.",
e);
}
catch (SecurityException e)
{
throw new SAXException(
"Error while instantiating a source transformer :"
+ " The security manager denies instantiation of the class "
+ className,
e);
}
return result;
}
}