/* * #%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; } }