/**
   * @param merged
   * @param xml
   * @param annotation
   */
  private static void merge(
      EnterpriseBeansMetaData merged,
      EnterpriseBeansMetaData xml,
      EnterpriseBeansMetaData annotation) {
    //
    HashMap<String, String> ejbClassToName = new HashMap<String, String>();
    if (xml != null) {
      if (xml.getId() != null) merged.setId(xml.getId());
      for (EnterpriseBeanMetaData bean : xml) {
        String className = bean.getEjbClass();
        if (className != null) {
          // Use the unqualified name
          int dot = className.lastIndexOf('.');
          if (dot >= 0) className = className.substring(dot + 1);
          ejbClassToName.put(className, bean.getEjbName());
        }
      }
    }

    // First get the annotation beans without an xml entry
    if (annotation != null) {
      for (EnterpriseBeanMetaData bean : annotation) {
        if (xml != null) {
          // This is either the ejb-name or the ejb-class simple name
          String ejbName = bean.getEjbName();
          EnterpriseBeanMetaData match = xml.get(ejbName);
          if (match == null) {
            // Lookup by the unqualified ejb class
            String xmlEjbName = ejbClassToName.get(ejbName);
            if (xmlEjbName == null) merged.add(bean);
          }
        } else {
          merged.add(bean);
        }
      }
    }
    // Now merge the xml and annotations
    if (xml != null) {
      for (EnterpriseBeanMetaData bean : xml) {
        EnterpriseBeanMetaData annBean = null;
        if (annotation != null) {
          String name = bean.getEjbName();
          annBean = annotation.get(name);
          if (annBean == null) {
            // Lookup by the unqualified ejb class
            String className = bean.getEjbClass();
            if (className != null) {
              // Use the unqualified name
              int dot = className.lastIndexOf('.');
              if (dot >= 0) className = className.substring(dot + 1);
              annBean = annotation.get(className);
            }
          }
        }
        // Merge
        EnterpriseBeanMetaData mbean = bean;
        if (annBean != null) {
          mbean = EnterpriseBeanMetaData.newBean(bean);
          mbean.merge(bean, annBean);
        }
        merged.add(mbean);
      }
    }
  }
  @Override
  protected void processElement(final EjbJarMetaData ejbJarMetaData, XMLStreamReader reader)
      throws XMLStreamException {
    final EjbJarElement ejbJarElement = EjbJarElement.forName(reader.getLocalName());
    switch (ejbJarElement) {
      case MODULE_NAME:
        // only EJB 3.1 allows module-name
        if (ejbJarMetaData.isEJB31()) {
          String moduleName = getElementText(reader);
          ejbJarMetaData.setModuleName(moduleName);
        } else {
          throw unexpectedElement(reader);
        }
        break;

      case ENTERPRISE_BEANS:
        EnterpriseBeansMetaData enterpriseBeans =
            EnterpriseBeansMetaDataParser.parse(reader, ejbJarMetaData.getEjbJarVersion());
        if (enterpriseBeans != null) {
          // setup the bi-directional relationship
          enterpriseBeans.setEjbJarMetaData(ejbJarMetaData);
        }
        ejbJarMetaData.setEnterpriseBeans(enterpriseBeans);
        break;

      case INTERCEPTORS:
        // only applicable for EJB 3.x
        if (ejbJarMetaData.isEJB3x()) {
          InterceptorsMetaData intercpetors = InterceptorsMetaDataParser.INSTANCE.parse(reader);
          ejbJarMetaData.setInterceptors(intercpetors);
        } else {
          throw unexpectedElement(reader);
        }
        break;

      case RELATIONSHIPS:
        RelationsMetaData relations = RelationsMetaDataParser.parse(reader);
        ejbJarMetaData.setRelationships(relations);
        break;

      case ASSEMBLY_DESCRIPTOR:
        AssemblyDescriptorMetaDataParser assemblyDescriptorParser =
            AssemblyDescriptorMetaDataParserFactory.getParser(ejbJarMetaData.getEjbJarVersion());
        ejbJarMetaData.setAssemblyDescriptor(assemblyDescriptorParser.parse(reader));
        break;

      case EJB_CLIENT_JAR:
        String ejbClientJar = getElementText(reader);
        ejbJarMetaData.setEjbClientJar(ejbClientJar);
        break;

      default:
        Accessor<DescriptionGroupMetaData> accessor =
            new Accessor<DescriptionGroupMetaData>() {
              @Override
              public DescriptionGroupMetaData get() {
                DescriptionGroupMetaData descriptionGroup = ejbJarMetaData.getDescriptionGroup();
                if (descriptionGroup == null) {
                  descriptionGroup = new DescriptionGroupMetaData();
                  ejbJarMetaData.setDescriptionGroup(descriptionGroup);
                }
                return descriptionGroup;
              }
            };
        if (DescriptionGroupMetaDataParser.parse(reader, accessor)) break;
        throw unexpectedElement(reader);
    }
  }