/* 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.
*/
package org.riotfamily.common.beans.override;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.riotfamily.common.beans.namespace.GenericBeanDefinitionParser;
import org.riotfamily.common.beans.namespace.GenericNamespaceHandlerSupport;
import org.riotfamily.common.xml.XmlUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
/**
* @author Felix Gnass [fgnass at neteye dot de]
* @since 6.5
*/
public class OverrideNamespaceHandler extends GenericNamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("if-present", new ConditionalParser());
registerBeanDefinitionParser("properties", new PropertyOverrideParser());
registerBeanDefinitionParser("put", new MapMergeParser());
registerBeanDefinitionParser("add", new ListMergeParser());
registerBeanDefinitionParser("bean", new BeanOverrideParser());
}
private static class ConditionalParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionParserDelegate delegate = parserContext.getDelegate();
BeanDefinitionRegistry registry = parserContext.getRegistry();
String ref = element.getAttribute("ref");
if (registry.containsBeanDefinition(ref)) {
for (Element child : XmlUtils.getChildElements(element)) {
if (delegate.isDefaultNamespace(child.getNamespaceURI())) {
BeanDefinitionHolder bdh = delegate.parseBeanDefinitionElement(child);
String id = bdh.getBeanName();
if (id != null) {
registry.registerBeanDefinition(id, bdh.getBeanDefinition());
}
}
else {
delegate.parseCustomElement(child);
}
}
}
return null;
}
}
private static class PropertyOverrideParser extends GenericBeanDefinitionParser {
public PropertyOverrideParser() {
super(PropertyOverrideProcessor.class);
}
@Override
protected void postProcess(BeanDefinitionBuilder beanDefinition,
ParserContext parserContext, Element element) {
BeanDefinition bd = new RootBeanDefinition();
parserContext.getDelegate().parsePropertyElements(element, bd);
beanDefinition.addPropertyValue("propertyValues", bd.getPropertyValues());
}
}
private static class MapMergeParser extends GenericBeanDefinitionParser {
public MapMergeParser() {
super(MapMergeProcessor.class);
}
@Override
@SuppressWarnings("unchecked")
protected void postProcess(BeanDefinitionBuilder beanDefinition,
ParserContext parserContext, Element element) {
Map entries = parserContext.getDelegate().parseMapElement(
element, beanDefinition.getBeanDefinition());
// The parsed Map is a ManagedMap. We put the values into a
// HashMap so that the reference resolution is deferred until
// the actual target bean is initialized.
beanDefinition.addPropertyValue("entries", new HashMap(entries));
}
}
private static class ListMergeParser extends GenericBeanDefinitionParser {
public ListMergeParser() {
super(ListMergeProcessor.class);
}
@Override
protected void postProcess(BeanDefinitionBuilder beanDefinition,
ParserContext parserContext, Element element) {
List<?> values = parserContext.getDelegate().parseListElement(
element, beanDefinition.getBeanDefinition());
// The parsed List is a ManagedList. We put the values into an
// ArrayList so that the reference resolution is deferred until
// the actual target bean is initialized.
beanDefinition.addPropertyValue("values", new ArrayList<Object>(values));
}
}
private static class BeanOverrideParser extends GenericBeanDefinitionParser {
public BeanOverrideParser() {
super(BeanOverrideProcessor.class);
}
@Override
protected boolean isEligibleAttribute(String attributeName,
ParserContext parserContext) {
return attributeName.equals("ref")
|| attributeName.equals("merge")
|| attributeName.equals("order");
}
@Override
protected void postProcess(BeanDefinitionBuilder builder,
ParserContext parserContext, Element element) {
BeanReplacement replacement = new BeanReplacement(
parserContext.getDelegate().parseBeanDefinitionElement(
element, null, builder.getBeanDefinition()));
builder.addPropertyValue("beanReplacement", replacement);
builder.getBeanDefinition().getPropertyValues().setConverted();
}
}
static class BeanReplacement {
private BeanDefinition beanDefinition;
public BeanReplacement(BeanDefinition beanDefinition) {
this.beanDefinition = beanDefinition;
}
public BeanDefinition getBeanDefinition() {
return this.beanDefinition;
}
}
}