net.phoenix.thrift.xml.ProcessorBeanDefinitionParser.java Source code

Java tutorial

Introduction

Here is the source code for net.phoenix.thrift.xml.ProcessorBeanDefinitionParser.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 net.phoenix.thrift.xml;

import java.util.HashMap;
import java.util.Map;

import net.phoenix.thrift.annotation.Processor;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.MethodInvokingBean;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedArray;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.w3c.dom.Element;

/**
 * TMultiplexedProcessor???Processor
 * ???springcontext-scan?? ??:
 * <ol>
 * <li>@Component(name)?componentnameServiceName
 * <code>TMultiplexedProcessor</code></li>
 * <li>@Processor(processor class) annotation?thrift ifaceprocessor
 * class?processorprocessorthrift??</li>
 * </ol>
 *
 * @author Shamphone Lee<shamphone@gmail.com>
 *
 */
public class ProcessorBeanDefinitionParser extends AbstractBeanDefinitionParser {
    private static Logger LOG = Logger.getLogger(ProcessorBeanDefinitionParser.class);
    private String beanName;
    private boolean multiplexed = false;

    /*
     * (non-Javadoc)
     *
     * @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#
     * parseInternal(org.w3c.dom.Element,
     * org.springframework.beans.factory.xml.ParserContext)
     */
    @Override
    protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
        this.beanName = this.parseBeanName(element);
        this.multiplexed = this.parseBoolean(element.getAttribute("multiplexed"));
        boolean autoScan = this.parseBoolean(element.getAttribute("auto-scan"));
        Map<String, BeanDefinition> processors = null;
        if (autoScan)
            processors = this.scanProcessors(parserContext);
        if (this.multiplexed) {
            BeanDefinitionBuilder root = BeanDefinitionBuilder.rootBeanDefinition(this.getServerClassName());
            if (processors != null) {
                for (Map.Entry<String, BeanDefinition> processor : processors.entrySet()) {
                    String serviceName = processor.getKey();
                    String processorBeanName = serviceName + "-Processor";
                    BeanDefinition processorBean = processor.getValue();
                    parserContext.getRegistry().registerBeanDefinition(processorBeanName, processorBean);
                    this.registerProcessor(parserContext, processor.getKey(), processorBeanName);
                    LOG.info("{msg: \"Thrift Service Registered\" " + ", service-name: \"" + serviceName + "\""
                            + ",processor-name: \"" + processorBeanName + "\"" + ",processor-class:"
                            + processorBean.getBeanClassName() + "}");
                }
            }
            AbstractBeanDefinition rootBean = root.getBeanDefinition();
            parserContext.getRegistry().registerBeanDefinition(this.beanName, rootBean);
            return rootBean;
        } else {
            if (processors == null || processors.size() == 0)
                throw new BeanCreationException("Could not found thrift service processors. ");
            if (processors.size() > 1)
                throw new BeanCreationException(
                        "More than one thrift service processors found, please change 'multiplexed' to true. ");
            BeanDefinition processor = processors.values().iterator().next();

            parserContext.getRegistry().registerBeanDefinition(this.beanName, processor);
            return (AbstractBeanDefinition) processor;
        }
    }

    private Class<?> getServerClassName() {
        try {
            return Class.forName("org.apache.thrift.TMultiplexedProcessor");
        } catch (ClassNotFoundException e) {
            throw new BeanCreationException(
                    "Could not found class for org.apache.thrift.TMultiplexedProcessor, make sure your thrift version is greater-equals than 0.9.1");
        }
    }

    private String parseBeanName(Element element) {
        String beanName = element.getAttribute("id");
        if (StringUtils.isEmpty(beanName)) {
            beanName = element.getAttribute("name");
        }
        if (StringUtils.isEmpty(beanName)) {
            beanName = "rpc-processor";
        }
        if (StringUtils.isEmpty(element.getAttribute("id"))) {
            element.setAttribute("id", beanName);
        }
        return beanName;
    }

    /**
     * context-scan???Iface
     * serviceparserContext?serviceprocesor
     */
    private Map<String, BeanDefinition> scanProcessors(ParserContext parserContext) {
        Map<String, BeanDefinition> processors = new HashMap<String, BeanDefinition>();
        for (String serviceName : parserContext.getRegistry().getBeanDefinitionNames()) {
            BeanDefinition serviceBeanDefinition = parserContext.getRegistry().getBeanDefinition(serviceName);
            Class<?> clazz;
            try {
                clazz = Class.forName(serviceBeanDefinition.getBeanClassName());
            } catch (ClassNotFoundException e) {
                throw new CannotLoadBeanClassException(parserContext.getReaderContext().getResource().getFilename(),
                        serviceName, serviceBeanDefinition.getBeanClassName(), e);
            }
            Processor annotation = AnnotationUtils.findAnnotation(clazz, Processor.class);
            if (annotation != null) {
                //processor class;
                Class<?> processorClass = annotation.processor();
                // build bean definition for processor;
                BeanDefinition processorBeanDefinition = this.createProcessorBean(processorClass, serviceName);
                processors.put(serviceName, processorBeanDefinition);
            }
        }
        return processors;
    }

    /**
     * Processorbean definition;
     *
     * @param processorClass
     *            processor??
     * @param serviceBeanDefinition
     *            servicebean name@Component?
     * @return
     */
    private BeanDefinition createProcessorBean(Class<?> processorClass, String serviceName) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(processorClass);
        builder.addConstructorArgReference(serviceName);
        return builder.getBeanDefinition();
    }

    /**
     * TMultiplexedProcessor.registerProcessor(String serviceName, TProcessor
     * processor) ?processor ?MethodInvokingFactoryBean?
     *
     * @param serviceName
     * @param processBeanName
     */
    private String registerProcessor(ParserContext parserContext, String serviceName, String processBeanName) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(MethodInvokingBean.class);
        builder.addPropertyReference("targetObject", this.beanName);
        builder.addPropertyValue("targetMethod", "registerProcessor");
        ManagedArray arguments = new ManagedArray(Object.class.getName(), 2);
        arguments.add(serviceName);
        arguments.add(new RuntimeBeanReference(processBeanName));
        builder.addPropertyValue("arguments", arguments);
        String registerProcessorBeanName = processBeanName + "-registerProcessor";
        parserContext.getRegistry().registerBeanDefinition(registerProcessorBeanName, builder.getBeanDefinition());
        return registerProcessorBeanName;
    }

    private boolean parseBoolean(String value) {
        if (StringUtils.isEmpty(value))
            return false;
        return value.equalsIgnoreCase("yes") || value.equalsIgnoreCase("true");
    }
}