/*
 * Copyright 2012 Grid Dynamics Consulting Services, Inc.
 *      http://www.griddynamics.com
 *
 * 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.griddynamics.banshun.xml;

import com.griddynamics.banshun.ExportRef;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.ObjectUtils;
import org.w3c.dom.Element;

import static com.griddynamics.banshun.xml.ParserUtils.*;
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_SINGLETON;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;


public class ExportBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

    /**
     * String to be appended to the exported bean name.
     */
    private static final String BEAN_NAME_SUFFIX = "-export-ref";


    @Override
    protected String getBeanClassName(Element element) {
        return Void.class.getCanonicalName();
    }

    @Override
    protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
        return element.getAttribute(REF_ATTR)
                + "$export"
                + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR
                + ObjectUtils.getIdentityHexString(definition);
    }

    @Override
    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
        BeanDefinitionRegistry registry = parserContext.getRegistry();

        String exportInterface = element.getAttribute(INTERFACE_ATTR);
        if (isBlank(exportInterface)) {
            return;
        }

        String exportBeanRef = element.getAttribute(REF_ATTR);
        if (isBlank(exportBeanRef)) {
            return;
        }

        String rootName = element.getAttribute(ROOT_ATTR);
        if (isBlank(rootName)) {
            rootName = DEFAULT_ROOT_FACTORY_NAME;
        }

        String exportName = element.getAttribute(NAME_ATTR);
        if (isBlank(exportName)) {
            exportName = exportBeanRef;
        }

        String exportRefName = exportName + BEAN_NAME_SUFFIX;
        if (registry.containsBeanDefinition(exportRefName)) {
            throw new BeanCreationException("Registry already contains bean with name: " + exportRefName);
        }

        ConstructorArgumentValues exportBeanConstructorArgValues = new ConstructorArgumentValues();
        exportBeanConstructorArgValues.addGenericArgumentValue(exportName);
        exportBeanConstructorArgValues.addGenericArgumentValue(findClass(
                exportInterface,
                exportBeanRef,
                parserContext.getReaderContext().getResource().getDescription()
        ));

        AbstractBeanDefinition exportBeanDef = rootBeanDefinition(ExportRef.class).getRawBeanDefinition();
        exportBeanDef.setConstructorArgumentValues(exportBeanConstructorArgValues);

        ConstructorArgumentValues voidBeanConstructorArgValues = new ConstructorArgumentValues();
        voidBeanConstructorArgValues.addGenericArgumentValue(exportBeanDef, ExportRef.class.getName());

        AbstractBeanDefinition voidBeanDef = rootBeanDefinition(Void.class).getRawBeanDefinition();
        voidBeanDef.setFactoryBeanName(rootName);
        voidBeanDef.setFactoryMethodName("export");
        voidBeanDef.setLazyInit(false);
        voidBeanDef.setScope(SCOPE_SINGLETON);
        voidBeanDef.setConstructorArgumentValues(voidBeanConstructorArgValues);
//        voidBeanDefinition.setDependsOn(new String[] { exportBeanRef }); TODO ?

        registry.registerBeanDefinition(exportRefName, voidBeanDef);
    }

}

@@ -93,16 +93,71 @@
 .com%0A *%0A
+ * Copyright 2013 Jakub Jirutka %3Cjakub@jirutka.cz%3E.%0A *%0A
  * Licen
@@ -909,24 +909,88 @@
 ctoryUtils;%0A
+import org.springframework.beans.factory.config.BeanDefinition;%0A
 import org.s
@@ -1270,16 +1270,85 @@
 gistry;%0A
+import org.springframework.beans.factory.support.RootBeanDefinition;%0A
 import o
@@ -1612,16 +1612,92 @@
 tils.*;%0A
+import static com.griddynamics.banshun.ContextParentBean.EXPORT_REF_SUFFIX;%0A
 import s
@@ -1965,148 +1965,8 @@
  %7B%0A%0A
-    /**%0A     * String to be appended to the exported bean name.%0A     */%0A    private static final String BEAN_NAME_SUFFIX = %22-export-ref%22;%0A%0A%0A
     
@@ -3233,25 +3233,26 @@
 tName + 
-BEAN_NAME
+EXPORT_REF
 _SUFFIX;
@@ -3834,33 +3834,32 @@
         ));%0A
-%0A
         
 AbstractBean
@@ -3842,32 +3842,24 @@
 ));%0A        
-Abstract
 BeanDefiniti
@@ -3869,33 +3869,37 @@
 exportBeanDef = 
-r
+new R
 ootBeanDefinitio
@@ -3919,41 +3919,9 @@
 lass
-).getRawBeanDefinition();%0A       
+,
  exp
@@ -3923,31 +3923,24 @@
 , exportBean
-Def.set
 ConstructorA
@@ -3945,50 +3945,20 @@
 rArg
-ument
 Values
-(exportBeanConstructorArgValues
+, null
 );%0A%0A
@@ -4239,172 +4239,224 @@
 ass)
-.getRawBeanDefinition();%0A        voidBeanDef.setFactoryBeanName(rootName);%0A        voidBeanDef.setFactoryMethodName(%22export%22);%0A        voidBeanDef.setLazyInit(false
+%0A                .setFactoryMethod(%22export%22)%0A                .setScope(SCOPE_SINGLETON)%0A                .setLazyInit(false)%0A                //.addDependsOn(exportBeanRef) TODO ?%0A                .getRawBeanDefinition(
 );%0A 
@@ -4477,37 +4477,40 @@
 nDef.set
-Scope(SCOPE_SINGLETON
+FactoryBeanName(rootName
 );%0A     
@@ -4587,90 +4587,8 @@
 es);
-%0A//        voidBeanDefinition.setDependsOn(new String%5B%5D %7B exportBeanRef %7D); TODO ?
 %0A%0A  

Refactor ExportBeanDefinitionParser a little bit