package com.firefly.core.support.xml.parse; import com.firefly.core.support.xml.*; import com.firefly.utils.ReflectUtils; import com.firefly.utils.StringUtils; import com.firefly.utils.VerifyUtils; import com.firefly.utils.dom.Dom; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import static com.firefly.core.support.annotation.AnnotationBeanUtils.*; import static com.firefly.core.support.xml.parse.XmlNodeConstants.*; public class BeanNodeParser extends AbstractXmlNodeParser implements XmlNodeParser { @Override public Object parse(Element ele, Dom dom) { // gets basic attribute String id = ele.getAttribute(ID_ATTRIBUTE); String className = ele.getAttribute(CLASS_ATTRIBUTE); XmlBeanDefinition xmlBeanDefinition = new XmlGenericBeanDefinition(); xmlBeanDefinition.setId(id); xmlBeanDefinition.setClassName(className); Class<?> clazz = null; log.info("classes [{}]", className); try { clazz = XmlBeanReader.class.getClassLoader().loadClass(className); } catch (Throwable e) { error("loads class \"" + className + "\" error"); } String initMethod = ele.getAttribute(INIT_METHOD_ATTRIBUTE); if (StringUtils.hasText(initMethod)) { try { Method method = clazz.getMethod(initMethod); xmlBeanDefinition.setInitMethod(method); } catch (NoSuchMethodException | SecurityException e) { error("the initial method " + initMethod + " not found"); } } else { xmlBeanDefinition.setInitMethod(getInitMethod(clazz)); } String destroyedMethod = ele.getAttribute(DESTORY_METHOD_ATTRIBUTE); if (StringUtils.hasText(destroyedMethod)) { try { Method method = clazz.getMethod(destroyedMethod); xmlBeanDefinition.setDestroyedMethod(method); } catch (NoSuchMethodException | SecurityException e) { error("the initial method " + initMethod + " not found"); } } else { xmlBeanDefinition.setDestroyedMethod(getDestroyedMethod(clazz)); } xmlBeanDefinition.setInjectFields(getInjectFields(clazz)); xmlBeanDefinition.setInjectMethods(getInjectMethods(clazz)); // gets bean's constructor List<Element> constructors = dom.elements(ele, CONTRUCTOR_ELEMENT); if (constructors != null && constructors.size() > 0) { Element constructorElement = constructors.get(0); List<Element> arguments = dom.elements(constructorElement, ARGUMENT_ELEMENT); if (arguments != null && arguments.size() >= 1) { List<Class<?>> argsClass = new ArrayList<>(); for (Element argument : arguments) { XmlManagedNode xmlManagedNode = parseXmlManagedNode(argument, dom); if (xmlManagedNode != null) { xmlBeanDefinition.getContructorParameters().add(xmlManagedNode); } String initArgsType = argument.getAttribute(TYPE_ATTRIBUTE); if (VerifyUtils.isNotEmpty(initArgsType)) { try { argsClass.add(XmlBeanReader.class.getClassLoader().loadClass(initArgsType)); } catch (ClassNotFoundException e) { error("The '" + initArgsType + "' not found"); } } else { error("The '" + className + "' constructor argument node MUST has type attribute"); } } try { xmlBeanDefinition.setConstructor(clazz.getConstructor(argsClass.toArray(new Class<?>[0]))); } catch (Throwable e) { error("The '" + className + "' gets constructor error"); } } else { error("The '" + className + "' constructor node MUST be more than one argument node!"); } } else { try { xmlBeanDefinition.setConstructor(clazz.getConstructor(new Class<?>[0])); } catch (Throwable e) { error("The '" + className + "' gets constructor error"); } } // gets all interface name String[] names = ReflectUtils.getInterfaceNames(clazz); xmlBeanDefinition.setInterfaceNames(names); log.debug("XML bean node parsing, class name [{}], interface size [{}]", className, names.length); // gets all properties List<Element> properties = dom.elements(ele, PROPERTY_ELEMENT); if (properties != null) { for (Element property : properties) { String name = property.getAttribute(NAME_ATTRIBUTE); XmlManagedNode xmlManagedNode = parseXmlManagedNode(property, dom); if (xmlManagedNode != null && VerifyUtils.isNotEmpty(name)) { xmlBeanDefinition.getProperties().put(name, xmlManagedNode); } } } return xmlBeanDefinition; } private XmlManagedNode parseXmlManagedNode(Element property, Dom dom) { boolean hasValueAttribute = property.hasAttribute(VALUE_ATTRIBUTE); boolean hasRefAttribute = property.hasAttribute(REF_ATTRIBUTE); // element types choose one of ref, value, list, etc. NodeList nl = property.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); ++i) { Node node = nl.item(i); if (node instanceof Element) { if (subElement != null) { error("This element must not contain more than one sub-element"); } else { subElement = (Element) node; } } } if (hasValueAttribute && hasRefAttribute || ((hasValueAttribute || hasRefAttribute) && subElement != null)) { error("This element is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element"); } if (hasValueAttribute) { // literal value String value = property.getAttribute(VALUE_ATTRIBUTE); if (!StringUtils.hasText(value)) { error("This element contains empty 'value' attribute"); } return new ManagedValue(value); } else if (hasRefAttribute) { // bean reference String ref = property.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(ref)) { error("This element contains empty 'ref' attribute"); } return new ManagedRef(ref); } else if (subElement != null) { // sub-elements return (XmlManagedNode) XmlNodeStateMachine.stateProcessor(subElement, dom); } else { error("This element must specify a ref or value"); return null; } } }