/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* 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 com.alibaba.citrus.service.pipeline.support;
import static com.alibaba.citrus.springext.util.DomUtil.*;
import static com.alibaba.citrus.springext.util.SpringExtUtil.*;
import static com.alibaba.citrus.util.ObjectUtil.*;
import static com.alibaba.citrus.util.StringUtil.*;
import java.util.List;
import com.alibaba.citrus.service.pipeline.Valve;
import com.alibaba.citrus.service.pipeline.impl.PipelineImpl;
import com.alibaba.citrus.service.pipeline.impl.condition.JexlCondition;
import com.alibaba.citrus.springext.ConfigurationPoint;
import com.alibaba.citrus.springext.Contribution;
import com.alibaba.citrus.springext.ContributionAware;
import com.alibaba.citrus.springext.support.parser.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
/**
* Valve解析器的基类。
*
* @author Michael Zhou
*/
public abstract class AbstractValveDefinitionParser<V extends Valve> extends AbstractSingleBeanDefinitionParser<V>
implements ContributionAware {
private ConfigurationPoint valvesConfigurationPoint;
private ConfigurationPoint conditionsConfigurationPoint;
public void setContribution(Contribution contrib) {
valvesConfigurationPoint = getSiblingConfigurationPoint("services/pipeline/valves", contrib);
conditionsConfigurationPoint = getSiblingConfigurationPoint("services/pipeline/conditions", contrib);
}
/** 取得pipeline bean。 */
protected final Object parsePipeline(Element element, ParserContext parserContext) {
return parsePipeline(element, null, parserContext);
}
protected final Object parsePipeline(Element element, Element labelElement, ParserContext parserContext) {
return parsePipeline(element, labelElement, parserContext, null, false);
}
protected final Object parsePipeline(Element element, Element labelElement, ParserContext parserContext,
String refAttribute) {
return parsePipeline(element, labelElement, parserContext, refAttribute, false);
}
protected final Object parsePipeline(Element element, Element labelElement, ParserContext parserContext,
String refAttribute, boolean returnNullIfNoValves) {
// pipeline可以是引用或作为inner-bean。
// 引用pipeline支持注入不同scope的pipeline,例如:注入一个request scope的pipeline scoped proxy。
String pipelineRef = trimToNull(element.getAttribute(defaultIfNull(trimToNull(refAttribute), "pipeline-ref")));
if (pipelineRef != null) {
return new RuntimeBeanReference(pipelineRef);
}
// parse pipeline as an inner-bean
BeanDefinitionBuilder pipelineBuilder = BeanDefinitionBuilder.genericBeanDefinition(PipelineImpl.class);
// label attribute所在的element通常是和定义子pipeline的element相同的,
// 但是对于多分支的子pipeline,例如:try-catch-finally,choose-when-otherwise等,可以把label定义在顶层element中。
if (labelElement == null) {
labelElement = element;
}
attributesToProperties(labelElement, pipelineBuilder, "label");
List<Object> valves = createManagedList(element, parserContext);
for (Element subElement : subElements(element)) {
Object valve = parseConfigurationPointBean(subElement, valvesConfigurationPoint, parserContext,
pipelineBuilder);
if (valve != null) {
valves.add(valve);
}
}
if (returnNullIfNoValves && valves.isEmpty()) {
return null;
}
pipelineBuilder.addPropertyValue("valves", valves);
return pipelineBuilder.getBeanDefinition();
}
/** 取得condition bean。 */
protected final Object parseCondition(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// 先试从test attribute中创建jexl condition
String jexl = trimToNull(element.getAttribute("test"));
if (jexl != null) {
BeanDefinitionBuilder conditionBuilder = BeanDefinitionBuilder.genericBeanDefinition(JexlCondition.class);
conditionBuilder.addPropertyValue("expression", jexl);
return conditionBuilder.getBeanDefinition();
}
// 再试从condition element中取得condition
for (Element subElement : subElements(element)) {
Object condition = parseConfigurationPointBean(subElement, conditionsConfigurationPoint, parserContext,
builder);
if (condition != null) {
return condition;
}
}
return null;
}
}