/*
* #%L
* carewebframework
* %%
* Copyright (C) 2008 - 2016 Regenstrief Institute, Inc.
* %%
* Licensed 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.
*
* This Source Code Form is also subject to the terms of the Health-Related
* Additional Disclaimer of Warranty and Limitation of Liability available at
*
* http://www.carewebframework.org/licensing/disclaimer.
*
* #L%
*/
package org.carewebframework.api.spring;
import java.io.IOException;
import org.carewebframework.api.spring.SpringUtil;
import org.carewebframework.common.XMLUtil;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.io.Resource;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Spring xml configuration file parser extension. This is an abstract base class for implementing
* CareWeb extensions to the Spring configuration xml schema.
*/
public class BaseXmlParser extends AbstractSingleBeanDefinitionParser {
/**
* Find the child element whose tag matches the specified tag name.
*
* @param tagName Tag name to locate.
* @param element Parent element whose children are to be searched.
* @return The matching node (first occurrence only) or null if not found.
*/
protected Element findTag(String tagName, Element element) {
Node result = element.getFirstChild();
while (result != null) {
if (result instanceof Element
&& (tagName.equals(((Element) result).getNodeName()) || tagName
.equals(((Element) result).getLocalName()))) {
break;
}
result = result.getNextSibling();
}
return (Element) result;
}
/**
* Returns the children under the specified tag. Compensates for namespace usage.
*
* @param tagName Name of tag whose children are sought.
* @param element Element to search for tag.
* @return Node list containing children of tag.
*/
protected NodeList getTagChildren(String tagName, Element element) {
return element.getNamespaceURI() == null ? element.getElementsByTagName(tagName) : element.getElementsByTagNameNS(
element.getNamespaceURI(), tagName);
}
/**
* Adds all attributes of the specified elements as properties in the current builder.
*
* @param element Element whose attributes are to be added.
* @param builder Target builder.
*/
protected void addProperties(Element element, BeanDefinitionBuilder builder) {
NamedNodeMap attributes = element.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
String attrName = getNodeName(node);
attrName = "class".equals(attrName) ? "clazz" : attrName;
builder.addPropertyValue(attrName, node.getNodeValue());
}
}
/**
* Returns the node name. First tries local name. If this is null, returns instead the full node
* name.
*
* @param node DOM node to examine.
* @return Name of the node.
*/
protected String getNodeName(Node node) {
String result = node.getLocalName();
return result == null ? node.getNodeName() : result;
}
/**
* Parses an xml extension from an xml string.
*
* @param xml XML containing the extension.
* @param tagName The top level tag name.
* @return Result of the parsed extension.
* @throws Exception Unspecified exception.
*/
protected Object fromXml(String xml, String tagName) throws Exception {
Document document = XMLUtil.parseXMLFromString(xml);
NodeList nodeList = document.getElementsByTagName(tagName);
if (nodeList == null || nodeList.getLength() != 1) {
throw new DOMException(DOMException.NOT_FOUND_ERR, "Top level tag '" + tagName + "' was not found.");
}
Element element = (Element) nodeList.item(0);
Class<?> beanClass = getBeanClass(element);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(beanClass);
doParse(element, builder);
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.setParentBeanFactory(SpringUtil.getAppContext());
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
factory.registerBeanDefinition(tagName, beanDefinition);
return factory.getBean(tagName);
}
/**
* Return the path of the resource being parsed.
*
* @param parserContext The current parser context.
* @return The resource being parsed, or null if cannot be determined.
*/
protected String getResourcePath(ParserContext parserContext) {
if (parserContext != null) {
try {
Resource resource = parserContext.getReaderContext().getResource();
return resource == null ? null : resource.getURL().getPath();
} catch (IOException e) {}
}
return null;
}
}