/*
* #%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.shell.plugins;
import java.util.Properties;
import org.carewebframework.api.spring.BaseXmlParser;
import org.carewebframework.shell.property.PropertyInfo;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Spring xml configuration file parser extension. Supports the definition of plugins within the
* configuration file in a much more abbreviated fashion than would be required without the
* extension.
*/
public class PluginXmlParser extends BaseXmlParser {
private enum ResourceType {
unknown, button, help, menu, property, css, bean, command, action
};
@Override
protected Class<?> getBeanClass(Element element) {
return PluginDefinition.class;
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
doParse(element, null, builder);
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.addDependsOn("manifestIterator");
builder.addPropertyValue("path", getResourcePath(parserContext));
addProperties(element, builder);
Element resourceTag = findTag("resource", element);
if (resourceTag != null) {
ManagedList<AbstractBeanDefinition> resourceList = new ManagedList<>();
NodeList resources = getTagChildren("resource", element);
for (int i = 0; i < resources.getLength(); i++) {
parseResources((Element) resources.item(i), builder, resourceList);
}
builder.addPropertyValue("resources", resourceList);
}
Element securityTag = findTag("security", element);
if (securityTag != null) {
addProperties(securityTag, builder);
ManagedList<AbstractBeanDefinition> authorityList = new ManagedList<>();
NodeList authorities = getTagChildren("security", element);
for (int i = 0; i < authorities.getLength(); i++) {
parseAuthorities((Element) authorities.item(i), builder, authorityList);
}
builder.addPropertyValue("authorities", authorityList);
}
Element serializationTag = findTag("serialization", element);
if (serializationTag != null) {
addProperties(serializationTag, builder);
ManagedList<AbstractBeanDefinition> propertyList = new ManagedList<>();
NodeList properties = getTagChildren("serialization", element);
for (int i = 0; i < properties.getLength(); i++) {
parseProperties((Element) properties.item(i), builder, propertyList);
}
builder.addPropertyValue("properties", propertyList);
}
}
/**
* Parse the resource list.
*
* @param element Root resource tag.
* @param builder Bean definition builder.
* @param resourceList List of resources to build.
*/
private void parseResources(Element element, BeanDefinitionBuilder builder,
ManagedList<AbstractBeanDefinition> resourceList) {
NodeList resources = element.getChildNodes();
for (int i = 0; i < resources.getLength(); i++) {
Node node = resources.item(i);
if (!(node instanceof Element)) {
continue;
}
Element resource = (Element) resources.item(i);
Class<? extends IPluginResource> resourceClass = null;
switch (getResourceType(getNodeName(resource))) {
case button:
resourceClass = PluginResourceButton.class;
break;
case help:
resourceClass = PluginResourceHelp.class;
break;
case menu:
resourceClass = PluginResourceMenu.class;
break;
case property:
resourceClass = PluginResourcePropertyGroup.class;
break;
case css:
resourceClass = PluginResourceCSS.class;
break;
case bean:
resourceClass = PluginResourceBean.class;
break;
case command:
resourceClass = PluginResourceCommand.class;
break;
case action:
resourceClass = PluginResourceAction.class;
break;
}
if (resourceClass != null) {
BeanDefinitionBuilder resourceBuilder = BeanDefinitionBuilder.genericBeanDefinition(resourceClass);
addProperties(resource, resourceBuilder);
resourceList.add(resourceBuilder.getBeanDefinition());
}
}
}
/**
* Parse the authority list.
*
* @param element Root authority tag.
* @param builder Bean definition builder.
* @param authorityList List of authorities to return.
*/
private void parseAuthorities(Element element, BeanDefinitionBuilder builder,
ManagedList<AbstractBeanDefinition> authorityList) {
NodeList authorities = element.getChildNodes();
for (int i = 0; i < authorities.getLength(); i++) {
Node node = authorities.item(i);
if (!(node instanceof Element)) {
continue;
}
Element authority = (Element) node;
BeanDefinitionBuilder authorityBuilder = BeanDefinitionBuilder
.genericBeanDefinition(PluginDefinition.Authority.class);
addProperties(authority, authorityBuilder);
authorityList.add(authorityBuilder.getBeanDefinition());
}
}
/**
* Parse the property list.
*
* @param element Root property tag.
* @param builder Bean definition builder.
* @param propertyList List of properties to return.
*/
private void parseProperties(Element element, BeanDefinitionBuilder builder,
ManagedList<AbstractBeanDefinition> propertyList) {
NodeList properties = element.getChildNodes();
for (int i = 0; i < properties.getLength(); i++) {
Node node = properties.item(i);
if (!(node instanceof Element)) {
continue;
}
Element property = (Element) node;
BeanDefinitionBuilder propertyBuilder = BeanDefinitionBuilder.genericBeanDefinition(PropertyInfo.class);
addProperties(property, propertyBuilder);
parseConfig(property, propertyBuilder);
propertyList.add(propertyBuilder.getBeanDefinition());
}
}
/**
* Parses out configuration settings for current property descriptor.
*
* @param property Root element
* @param propertyBuilder Bean definition builder.
*/
private void parseConfig(Element property, BeanDefinitionBuilder propertyBuilder) {
Element config = (Element) getTagChildren("config", property).item(0);
if (config != null) {
Properties properties = new Properties();
NodeList entries = getTagChildren("entry", config);
for (int i = 0; i < entries.getLength(); i++) {
Element entry = (Element) entries.item(i);
String key = entry.getAttribute("key");
String value = entry.getTextContent().trim();
properties.put(key, value);
}
propertyBuilder.addPropertyValue("config", properties);
}
}
/**
* Returns the ResourceType enum value corresponding to the resource tag.
*
* @param resourceTag Tag name of resource
* @return ResourceType enum. Returns an enum of unknown if tag is not a supported resource
* type.
*/
private ResourceType getResourceType(String resourceTag) {
if (resourceTag == null || !resourceTag.endsWith("-resource")) {
return ResourceType.unknown;
}
try {
return ResourceType.valueOf(resourceTag.substring(0, resourceTag.length() - 9));
} catch (Exception e) {
return ResourceType.unknown;
}
}
/**
* Parses a plugin definition from an xml string.
*
* @param xml XML containing plugin definition.
* @return A plugin definition instance.
* @throws Exception Unspecified exception.
*/
public static PluginDefinition fromXml(String xml) throws Exception {
return (PluginDefinition) new PluginXmlParser().fromXml(xml, "plugin");
}
}