com.caucho.config.xml.XmlConfigContext Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of resin-kernel Show documentation
Show all versions of resin-kernel Show documentation
Kernel for Resin Java Application Server
The newest version!
/*
* Copyright (c) 1998-2012 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*/
package com.caucho.config.xml;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.el.ELContext;
import javax.el.ELException;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.InjectionPoint;
import org.w3c.dom.Attr;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.caucho.config.Config;
import com.caucho.config.ConfigELContext;
import com.caucho.config.ConfigException;
import com.caucho.config.LineConfigException;
import com.caucho.config.attribute.Attribute;
import com.caucho.config.inject.CreationalContextImpl;
import com.caucho.config.inject.InjectManager;
import com.caucho.config.program.ConfigProgram;
import com.caucho.config.program.NodeBuilderChildProgram;
import com.caucho.config.program.RecoverableProgram;
import com.caucho.config.type.ConfigType;
import com.caucho.config.type.StringType;
import com.caucho.config.type.TypeFactory;
import com.caucho.el.ELParser;
import com.caucho.el.Expr;
import com.caucho.inject.Module;
import com.caucho.util.CompileException;
import com.caucho.util.DisplayableException;
import com.caucho.util.L10N;
import com.caucho.util.LineCompileException;
import com.caucho.vfs.Depend;
import com.caucho.vfs.Dependency;
import com.caucho.vfs.Path;
import com.caucho.vfs.ReadStream;
import com.caucho.vfs.Vfs;
import com.caucho.xml.QAbstractNode;
import com.caucho.xml.QAttributedNode;
import com.caucho.xml.QDocument;
import com.caucho.xml.QElement;
import com.caucho.xml.QName;
import com.caucho.xml.QNode;
import com.caucho.xml.XmlUtil;
/**
* The ConfigContext contains the state of the current configuration.
*/
@Module
public class XmlConfigContext {
private final static L10N L = new L10N(XmlConfigContext.class);
private final static Logger log
= Logger.getLogger(XmlConfigContext.class.getName());
public final static QName TEXT = new QName("#text");
private final static Object NULL = new Object();
private static ThreadLocal _currentBuilder
= new ThreadLocal();
private Config _config;
private InjectionPoint _ij;
private CreationalContextImpl> _beanStack;
private ArrayList _dependList;
private Document _dependDocument;
private String _baseUri;
public XmlConfigContext()
{
}
public XmlConfigContext(XmlConfigContext parent)
{
this();
}
public XmlConfigContext(Config config)
{
this();
_config = config;
}
public static XmlConfigContext create()
{
XmlConfigContext env = _currentBuilder.get();
if (env != null)
return env;
else
return new XmlConfigContext();
}
public static XmlConfigContext createForProgram()
{
return new XmlConfigContext();
}
public static XmlConfigContext getCurrentBuilder()
{
return _currentBuilder.get();
}
public static XmlConfigContext getCurrent()
{
return _currentBuilder.get();
}
// s/b private?
static void setCurrentBuilder(XmlConfigContext builder)
{
_currentBuilder.set(builder);
}
public InjectionPoint getInjectionPoint()
{
return _ij;
}
public void setInjectionPoint(InjectionPoint ij)
{
_ij = ij;
}
/**
* Returns the file var
*/
public String getBaseUri()
{
return Vfs.decode(_baseUri);
}
/**
* Returns the component value for the dependent scope
*
* @param aThis
* @return
*/
public Object get(Bean> bean)
{
return CreationalContextImpl.find(_beanStack, bean);
}
public Object findByName(String name)
{
return CreationalContextImpl.findByName(_beanStack, name);
}
public CreationalContext> setCreationalContext(CreationalContext> cxt)
{
CreationalContext> oldCxt = _beanStack;
_beanStack = (CreationalContextImpl>) cxt;
return oldCxt;
}
public CreationalContext> getCreationalContext()
{
return _beanStack;
}
public Config getConfig()
{
return _config;
}
/**
* Returns true if EL expressions are used.
*/
private boolean isEL()
{
// server/26b6
return _config == null || _config.isEL();
}
public boolean isIgnoreEnvironment()
{
return _config != null && _config.isIgnoreEnvironment();
}
/**
* External call to configure a bean based on a top-level node.
* The init() and replaceObject() are not called.
*
* @param bean the object to be configured.
*/
public Object configure(Object bean, Node top)
throws LineConfigException
{
if (bean == null)
throw new NullPointerException(L.l("unexpected null bean at node '{0}'", top));
XmlConfigContext oldBuilder = _currentBuilder.get();
try {
_currentBuilder.set(this);
ConfigType> type = TypeFactory.getType(bean);
configureBean(bean, top);
type.init(bean);
return type.replaceObject(bean);
} catch (LineConfigException e) {
throw e;
} catch (Exception e) {
throw error(e, top);
} finally {
_currentBuilder.set(oldBuilder);
}
}
/**
* External call to configure a bean based on a top-level node, calling
* init() and replaceObject() when done.
*
* @param bean the bean to be configured
* @param top the top-level XML configuration node
* @return the configured object, or the factory generated object
*/
public void configureBean(Object bean, Node top)
throws LineConfigException
{
XmlConfigContext oldBuilder = _currentBuilder.get();
String oldFile = _baseUri;
ArrayList oldDependList = _dependList;
try {
_currentBuilder.set(this);
if (top instanceof QNode) {
QNode qNode = (QNode) top;
_baseUri = qNode.getBaseURI();
}
_dependList = getDependencyList(top);
ConfigType> type = TypeFactory.getType(bean);
configureNode(top, bean, type);
} finally {
_currentBuilder.set(oldBuilder);
_dependList = oldDependList;
_baseUri = oldFile;
}
}
/**
* External call to configure a bean's attribute.
*
* @param bean the bean to be configured
* @param attribute the node representing the configured attribute
* @throws LineConfigException
*/
public void configureAttribute(Object bean, Node attribute)
throws LineConfigException
{
String attrName = attribute.getNodeName();
if (attrName.startsWith("xmlns"))
return;
String oldFile = _baseUri;
Thread thread = Thread.currentThread();
ClassLoader oldLoader = thread.getContextClassLoader();
XmlConfigContext oldBuilder = getCurrentBuilder();
try {
setCurrentBuilder(this);
_baseUri = attribute.getBaseURI();
ConfigType> type = TypeFactory.getType(bean);
QName qName = ((QAbstractNode) attribute).getQName();
type.beforeConfigure(this, bean, attribute);
configureChildNode(attribute, qName, bean, type, false);
type.afterConfigure(this, bean);
}
catch (LineConfigException e) {
throw e;
}
catch (Exception e) {
throw error(e, attribute);
} finally {
_baseUri = oldFile;
setCurrentBuilder(oldBuilder);
thread.setContextClassLoader(oldLoader);
}
}
/**
* Configures a bean, calling its init() and replaceObject() methods.
*
* @param typeStrategy the strategy for handling the bean's type
* @param bean the bean instance
* @param top the configuration top
* @return the configured bean, possibly the replaced object
* @throws LineConfigException
*/
public Object configureNode(Node node,
Object bean,
ConfigType> beanType)
throws LineConfigException
{
Thread thread = Thread.currentThread();
ClassLoader oldLoader = thread.getContextClassLoader();
try {
beanType.beforeConfigure(this, bean, node);
beanType.beforeConfigureBean(this, bean, node);
if (log.isLoggable(Level.ALL))
log.log(Level.ALL, "config begin " + beanType);
configureNodeAttributes(node, bean, beanType);
for (Node childNode = node.getFirstChild();
childNode != null;
childNode = childNode.getNextSibling()) {
QName qName = ((QAbstractNode) childNode).getQName();
configureChildNode(childNode, qName, bean, beanType, false);
}
if (log.isLoggable(Level.ALL))
log.log(Level.ALL, "config end " + beanType);
beanType.afterConfigure(this, bean);
} catch (LineConfigException e) {
throw e;
} catch (Exception e) {
throw error(e, node);
} finally {
thread.setContextClassLoader(oldLoader);
}
return bean;
}
/**
* Configures a bean, calling its init() and replaceObject() methods.
*
* @param typeStrategy the strategy for handling the bean's type
* @param bean the bean instance
* @param top the configuration top
* @return the configured bean, possibly the replaced object
* @throws LineConfigException
*/
private void configureNodeAttributes(Node node,
Object bean,
ConfigType> type)
{
if (node instanceof QAttributedNode) {
Node child = ((QAttributedNode) node).getFirstAttribute();
for (; child != null; child = child.getNextSibling()) {
Attr attr = (Attr) child;
QName qName = ((QNode) attr).getQName();
configureChildNode(attr, qName, bean, type, false);
}
}
else {
NamedNodeMap attrList = node.getAttributes();
if (attrList != null) {
int length = attrList.getLength();
for (int i = 0; i < length; i++) {
Attr attr = (Attr) attrList.item(i);
QName qName = ((QNode) attr).getQName();
configureChildNode(attr, qName, bean, type, false);
}
}
}
}
/**
* Configures a child node for a bean.
*
* Properties and fields will be set.
* Flow will be invoked (like resin:if)
*/
private void configureChildNode(Node childNode,
QName qName,
Object parentBean,
ConfigType> parentType,
boolean allowParam)
{
if (qName.getName().startsWith("xmlns")) {
return;
}
Attribute attrStrategy;
try {
attrStrategy = getAttribute(parentType, qName, childNode);
if (attrStrategy == null) {
if (qName.equals(TEXT)) {
validateEmptyText(parentBean, childNode);
}
}
else if (attrStrategy.isProgram()) {
attrStrategy.setValue(parentBean, qName,
buildProgram(attrStrategy, childNode));
}
else if (attrStrategy.isNode()) {
attrStrategy.setValue(parentBean, qName, childNode);
}
else if (configureInlineText(parentBean, childNode, qName, attrStrategy)) {
}
else if (configureInlineBean(parentBean, childNode, attrStrategy)) {
}
else {
configureBeanProperties(childNode, qName, parentBean,
parentType, attrStrategy,
allowParam);
}
} catch (LineConfigException e) {
throw e;
} catch (Exception e) {
throw error(e, childNode);
}
}
private void validateEmptyText(Object bean, Node childNode)
{
CharacterData cData = (CharacterData) childNode;
String data = cData.getData().trim();
if (data.length() > 0) {
throw new ConfigException(L.l("Unexpected text in {0} at\n '{1}'",
bean.getClass().getName(),
data));
}
}
private Attribute getAttribute(ConfigType> type,
QName qName,
Node childNode)
{
Attribute attrStrategy;
attrStrategy = type.getAttribute(qName);
if (attrStrategy == null) {
attrStrategy = type.getDefaultAttribute(qName);
}
if (attrStrategy != null) {
return attrStrategy;
}
if (childNode instanceof Element || childNode instanceof Attr) {
String localName = qName.getLocalName();
if (localName.indexOf(':') >= 0) {
// XXX: need ioc QA
throw error(L.l("'{0}' does not have a defined namespace for 'xmlns:{1}'. Tags with prefixes need defined namespaces.",
qName.getName(),
localName.substring(0, localName.indexOf(':'))),
childNode);
}
// ioc/23m2
if ("new".equals(localName)) {
return null;
}
throw error(L.l("'{0}' is an unknown property of '{1}'.",
qName.getName(), type.getTypeName()),
childNode);
}
return null;
}
private void setText(Object bean,
QName qName,
String text,
Attribute attrStrategy,
boolean isTrim)
{
ConfigType> attrType = attrStrategy.getConfigType();
if (isTrim && ! attrType.isNoTrim())
text = text.trim();
if (isEL() && attrType.isEL() && text.indexOf("${") >= 0) {
Object value = attrType.valueOf(evalObject(text));
attrStrategy.setValue(bean, qName, value);
}
else
attrStrategy.setText(bean, qName, text);
}
private boolean configureInlineText(Object bean,
Node childNode,
QName qName,
Attribute attrStrategy)
{
// ioc/2013
if (! attrStrategy.isSetter())
return false;
boolean isTrim = ! attrStrategy.getConfigType().isNoTrim();
String text = getTextValue(childNode, isTrim);
if (text == null)
return false;
isTrim = isTrim(childNode);
if (isEL() && attrStrategy.isEL()
&& (text.indexOf("#{") >= 0 || text.indexOf("${") >= 0)) {
if (isTrim)
text = text.trim();
Object elValue = eval(attrStrategy.getConfigType(), text);
// ioc/2410
if (elValue != NULL) {
attrStrategy.setValue(bean, qName, elValue);
}
else {
try {
attrStrategy.setValue(bean, qName, null);
} catch (Exception e) {
throw ConfigException.create(L.l("{0} value must not be null.\n ", text), e);
}
}
return true;
}
else if (attrStrategy.isAllowText()) {
setText(bean, qName, text, attrStrategy, isTrim);
return true;
}
else
return false;
}
private boolean configureInlineBean(Object parent,
Node node,
Attribute attrStrategy)
{
/* server/0219
if (! attrStrategy.isAllowInline()) {
return false;
}
*/
Node childNode = getChildElement(node);
if (childNode == null) {
return false;
}
QName parentQname = ((QNode) node).getQName();
QName childQname = ((QNode) childNode).getQName();
ConfigType> type = TypeFactory.getFactory().getEnvironmentType(childQname);
if (type == null || ! attrStrategy.isInlineType(type)) {
// server/6500
return false;
}
// server/0219
// Object childBean = attrStrategy.create(parent, qName, type);
Element childNew = getChildNewElement(childNode);
Object childBean;
if (childNew != null)
childBean = createNew(type, parent, childNew);
else if (type.isQualifier()) {
// ioc/04f8
Object qualifier = type.create(parent, childQname);
ConfigType> qualifierType = TypeFactory.getType(qualifier);
qualifier = configureChildBean(qualifier, qualifierType,
childNode, attrStrategy);
InjectManager cdiManager = InjectManager.getCurrent();
Class> attrType = attrStrategy.getConfigType().getType();
Set> beans
= cdiManager.getBeans(attrType, (Annotation) qualifier);
Bean> bean = cdiManager.resolve(beans);
CreationalContext cxt = null;
childBean = cdiManager.getReference(bean, attrType, cxt);
}
else
childBean = type.create(parent, childQname);
if (childBean == null)
return false;
// server/1af3
ConfigType> childType = TypeFactory.getType(childBean);
childBean = configureChildBean(childBean, childType,
childNode, attrStrategy);
// ejb/7006
attrStrategy.setValue(parent, parentQname, childBean);
return true;
}
private void configureBeanProperties(Node childNode,
QName qName,
Object bean,
ConfigType> type,
Attribute attrStrategy,
boolean allowParam)
{
Object childBean = attrStrategy.create(bean, qName);
if (childBean == null) {
throw unableToCreateError(attrStrategy, bean, qName, childNode);
}
ConfigType> childBeanType = TypeFactory.getType(childBean);
//ConfigType> childBeanType = attrStrategy.getType(childBean);
childBean = configureChildBean(childBean, childBeanType,
childNode, attrStrategy);
if (! childBeanType.isEnvBean()) {
attrStrategy.setValue(bean, qName, childBean);
}
}
private Object configureChildBean(Object childBean,
ConfigType> childBeanType,
Node childNode,
Attribute attrStrategy)
{
if (childNode instanceof Element) {
configureNode(childNode, childBean, childBeanType);
}
else
configureChildNode(childNode, TEXT, childBean, childBeanType, false);
childBeanType.init(childBean);
Object newBean = attrStrategy.replaceObject(childBean);
if (newBean == childBean)
return childBeanType.replaceObject(childBean);
else
return newBean;
}
private ConfigException unableToCreateError(Attribute attr,
Object bean,
QName qName,
Node node)
{
Element child = getUniqueChildElement(node);
if (child == null) {
throw error(L.l("unable to create inline attribute '{2}' for '{1}' because no unique child Element exists. Attribute = {0}",
attr, bean, qName),
node);
}
QName childQName = ((QNode) child).getQName();
String uri = childQName.getNamespaceURI();
if (uri == null || ! uri.startsWith("urn:java:")) {
throw error(L.l("unable to create inline attribute '{0}' for '{1}' because the child <{2}> uri must start with xmlns='urn:java:...' but uri='{3}' for {4}",
qName.getName(), bean, childQName.getName(), uri, attr),
node);
}
throw throwUnableToCreateError(attr, bean, qName, node);
}
private ConfigException throwUnableToCreateError(Attribute attr,
Object bean,
QName qName,
Node childNode)
{
throw error(L.l("unable to create attribute {0} for {1} and {2}",
attr, bean, qName),
childNode);
}
private Node getChildElement(Node node)
{
Element child = getUniqueChildElement(node);
if (child == null)
return null;
QName qName = ((QNode) child).getQName();
String uri = qName.getNamespaceURI();
if (uri == null || ! uri.startsWith("urn:java:"))
return null;
return child;
}
private Element getUniqueChildElement(Node node)
{
if (! (node instanceof Element))
return null;
Element elt = (Element) node;
Node child = elt.getFirstChild();
if (child == null)
return null;
if (isEmptyText(child)) {
child = child.getNextSibling();
if (child == null)
return null;
}
Node next = child.getNextSibling();
if (next != null) {
if (next.getNextSibling() != null || ! isEmptyText(next))
return null;
}
if (child instanceof Element)
return (Element) child;
else
return null;
}
private Object createNew(ConfigType> type,
Object parent,
Element newNode)
{
boolean isTrim = true;
String text = getTextValue(newNode, isTrim);
if (text != null) {
text = text.trim();
return type.valueOf(create(newNode, StringType.TYPE));
}
int count = countNewChildren(newNode);
Constructor> ctor = type.getConstructor(count);
Class> []paramTypes = ctor.getParameterTypes();
Object []args = new Object[paramTypes.length];
int i = 0;
for (Node child = newNode.getFirstChild();
child != null;
child = child.getNextSibling()) {
if (! (child instanceof Element))
continue;
ConfigType> childType = TypeFactory.getType(paramTypes[i]);
args[i++] = create(child, childType);
}
try {
return ctor.newInstance(args);
} catch (InvocationTargetException e) {
throw ConfigException.create(ctor.getName(), e.getCause());
} catch (Exception e) {
throw ConfigException.create(ctor.getName(), e);
}
}
private int countNewChildren(Element newNode)
{
int count = 0;
for (Node child = newNode.getFirstChild();
child != null;
child = child.getNextSibling()) {
if (child instanceof Element)
count++;
}
return count;
}
private Element getChildNewElement(Node node)
{
if (! (node instanceof Element))
return null;
Element elt = (Element) node;
for (Node child = elt.getFirstChild();
child != null;
child = child.getNextSibling()) {
if ("new".equals(child.getLocalName()))
return (Element) child;
}
return null;
}
private boolean isEmptyText(Node node)
{
if (! (node instanceof CharacterData))
return false;
CharacterData data = (CharacterData) node;
return data.getData().trim().length() == 0;
}
private boolean isTrim(Node node)
{
if (node instanceof Attr)
return false;
else if (node instanceof Element) {
Element elt = (Element) node;
if (! "".equals(elt.getAttribute("xml:space")))
return false;
}
return true;
}
private ConfigProgram buildProgram(Attribute attr, Node node)
{
ConfigProgram program = new NodeBuilderChildProgram(node);
if (Boolean.TRUE.equals(Config.getProperty(RecoverableProgram.ATTR))) {
program = new RecoverableProgram(program);
}
return program;
}
//
// Used for args
//
public Object create(Node childNode, ConfigType> type)
throws ConfigException
{
try {
Object childBean;
String text;
if ((text = getArgTextValue(childNode)) != null) {
boolean isTrim = isTrim(childNode);
if (isEL() && type.isEL()
&& (text.indexOf("#{") >= 0 || text.indexOf("${") >= 0)) {
if (isTrim)
text = text.trim();
Object elValue = eval(type, text);
// ioc/2410
if (elValue != NULL)
return elValue;
else
return null;
}
else {
return type.valueOf(text);
}
}
QName qName = ((QNode) childNode).getQName();
ConfigType> childBeanType = type.createType(qName);
if (childBeanType != null) {
childBean = childBeanType.create(null, qName);
if (childNode instanceof Element)
configureNode(childNode, childBean, childBeanType);
else
configureChildNode(childNode, TEXT, childBean, childBeanType, false);
childBeanType.init(childBean);
return childBeanType.replaceObject(childBean);
}
else {
String textValue;
if (type.isNoTrim())
textValue = textValueNoTrim(childNode);
else
textValue = textValue(childNode);
if (isEL() && type.isEL() && textValue.indexOf("${") >= 0) {
Object value = type.valueOf(evalObject(textValue));
return value;
}
else
return type.valueOf(textValue);
}
} catch (LineConfigException e) {
throw e;
} catch (Exception e) {
throw error(e, childNode);
}
}
Object configureValue(Node node)
{
String value = textValue(node);
if (isEL() && value != null
&& value.startsWith("${") && value.endsWith("}")) {
return evalObject(value);
}
else
return value;
}
public ArrayList getDependencyList()
{
return _dependList;
}
ArrayList getDependencyList(Node node)
{
ArrayList dependList = null;
if (node instanceof QElement) {
QElement qelt = (QElement) node;
QDocument doc = (QDocument) qelt.getOwnerDocument();
if (doc == null)
return null;
else if (doc == _dependDocument)
return _dependList;
_dependDocument = doc;
ArrayList pathList;
pathList = doc.getDependList();
if (pathList != null) {
dependList = new ArrayList();
for (int i = 0; i < pathList.size(); i++) {
dependList.add(new Depend(pathList.get(i)));
}
}
_dependList = dependList;
}
return dependList;
}
/**
* Returns the variable resolver.
*/
public static ConfigELContext getELContext()
{
return ConfigELContext.EL_CONTEXT;
}
/**
* Returns the text value of the node.
*/
private String getTextValue(Node node, boolean isTrim)
{
if (node instanceof Attr) {
Attr attrNode = (Attr) node;
String data = attrNode.getNodeValue();
return data;
}
else if (node instanceof CharacterData) {
CharacterData cData = (CharacterData) node;
return cData.getData();
}
if (! (node instanceof Element))
return null;
QElement elt = (QElement) node;
// ioc/2235
for (Node attr = elt.getFirstAttribute();
attr != null;
attr = attr.getNextSibling()) {
if (! "xml".equals(attr.getPrefix()))
return null;
}
for (Node child = elt.getFirstChild();
child != null;
child = child.getNextSibling()) {
if (child instanceof Element) {
return null;
}
else if (child instanceof CharacterData) {
String data = ((CharacterData) child).getData();
if (child.getNextSibling() != null) {
return null;
}
else if (! isTrim || ! XmlUtil.isWhitespace(data)) {
return data;
}
else {
return null;
}
}
}
return "";
}
/**
* Returns the text value of the node.
*/
private String getArgTextValue(Node node)
{
if (node instanceof Element && ! node.getLocalName().equals("value"))
return null;
boolean isTrim = true;
return getTextValue(node, isTrim);
}
private Object eval(ConfigType> type, String data)
{
ELContext elContext = getELContext();
ELParser parser = new ELParser(elContext, data);
Expr expr = parser.parse();
Object value = type.valueOf(elContext, expr);
if (value != null)
return value;
else
return NULL;
}
/**
* Returns the text value of the node.
*/
private static String textValue(Node node)
{
if (node instanceof Attr)
return node.getNodeValue();
else {
String value = XmlUtil.textValue(node);
if (value == null || value.equals(""))
return "";
else if (node instanceof Element) {
String space = ((Element) node).getAttribute("xml:space");
if (! space.equals(""))
return value;
}
return value.trim();
}
}
/**
* Returns the text value of the node.
*/
private static String textValueNoTrim(Node node)
{
if (node instanceof Attr)
return node.getNodeValue();
else {
String value = XmlUtil.textValue(node);
if (value == null)
return "";
return value;
}
}
/**
* Evaluate as an object
*/
private Object evalObject(String exprString)
throws ELException
{
if (exprString.indexOf("${") >= 0 && isEL()) {
ELParser parser = new ELParser(getELContext(), exprString);
parser.setCheckEscape(true);
Expr expr = parser.parse();
return expr.getValue(getELContext());
}
else
return exprString;
}
private static RuntimeException error(String msg, Node node)
{
String systemId = null;
String filename = null;
int line = 0;
if (node instanceof QAbstractNode) {
QAbstractNode qnode = (QAbstractNode) node;
systemId = qnode.getBaseURI();
filename = qnode.getFilename();
line = qnode.getLine();
}
if (systemId != null) {
String sourceLines = getSourceLines(systemId, line);
msg = msg + sourceLines;
}
if (filename != null)
return new LineConfigException(filename, line, msg);
else
return new LineConfigException(msg);
}
private static RuntimeException error(Throwable e, Node node)
{
String systemId = null;
String filename = null;
int line = 0;
if (e instanceof RuntimeException
&& e instanceof DisplayableException
&& ! ConfigException.class.equals(e.getClass())) {
return (RuntimeException) e;
}
if (node instanceof QAbstractNode) {
QAbstractNode qnode = (QAbstractNode) node;
systemId = qnode.getBaseURI();
filename = qnode.getFilename();
line = qnode.getLine();
}
for (; e.getCause() != null; e = e.getCause()) {
if (e instanceof LineCompileException)
break;
else if (e instanceof LineConfigException)
break;
else if (e instanceof CompileException)
break;
}
if (e instanceof LineConfigException)
return (LineConfigException) e;
else if (e instanceof LineCompileException) {
return new LineConfigException(e.getMessage(), e);
}
else if (e instanceof ConfigException
&& e.getMessage() != null
&& filename != null) {
String sourceLines = getSourceLines(systemId, line);
if (! systemId.startsWith("file:")) {
filename = systemId;
}
return new LineConfigException(filename, line,
e.getMessage() + sourceLines,
e);
}
else if (e instanceof CompileException && e.getMessage() != null) {
return new LineConfigException(filename, line, e);
}
else {
String sourceLines = getSourceLines(systemId, line);
String msg = filename + ":" + line + ": " + e + sourceLines;
if (e instanceof RuntimeException) {
throw new LineConfigException(msg, e);
}
else if (e instanceof Error) {
// server/1711
throw new LineConfigException(msg, e);
// throw (Error) e;
}
else
return new LineConfigException(msg, e);
}
}
private static String getSourceLines(String systemId, int errorLine)
{
if (systemId == null)
return "";
ReadStream is = null;
try {
is = Vfs.lookup().lookup(systemId).openRead();
int line = 0;
StringBuilder sb = new StringBuilder("\n\n");
String text;
while ((text = is.readLine()) != null) {
line++;
if (errorLine - 2 <= line && line <= errorLine + 2) {
sb.append(line);
sb.append(": ");
sb.append(text);
sb.append("\n");
}
}
return sb.toString();
} catch (IOException e) {
log.log(Level.FINEST, e.toString(), e);
return "";
} finally {
if (is != null)
is.close();
}
}
@Override
public String toString()
{
return getClass().getSimpleName() + "[]";
}
}