public MemberAnnotationHandler getHandlerForMemberAnnotation(String annotationName) {
    if (memberAnnotationHandlerAnnotations == null
        || !memberAnnotationHandlerAnnotations.contains(annotationName)) {
      return null;
    }

    MemberAnnotationHandler handler = memberAnnotationHandlers.get(annotationName);
    if (handler == null) {
      // Try to create this MemberAnnotationHandler
      try {
        PluginManager pluginMgr = metadataMgr.getNucleusContext().getPluginManager();
        handler =
            (MemberAnnotationHandler)
                pluginMgr.createExecutableExtension(
                    "org.datanucleus.member_annotation_handler",
                    "annotation-class",
                    annotationName,
                    "handler",
                    null,
                    null);
        memberAnnotationHandlers.put(annotationName, handler);
      } catch (Exception e) {
        NucleusLogger.METADATA.warn(
            Localiser.msg("MetaData.MemberAnnotationHandlerNotFound", annotationName));
        return null;
      }
    }

    return handler;
  }
  /**
   * Accessor for the MetaData for the specified class, read from annotations. The annotations can
   * be of any supported type.
   *
   * @param cls The class
   * @param pmd PackageMetaData to use as a parent
   * @param clr ClassLoader resolver
   * @return The ClassMetaData
   */
  public AbstractClassMetaData getMetaDataForClass(
      Class cls, PackageMetaData pmd, ClassLoaderResolver clr) {
    if (cls == null) {
      return null;
    }

    Annotation[] annotations = cls.getAnnotations();
    if (annotations == null || annotations.length == 0) {
      return null;
    }

    // Find an annotation reader for this classes annotations (if we have one)
    String readerClassName = null;
    for (int i = 0; i < annotations.length; i++) {
      String reader = annotationReaderLookup.get(annotations[i].annotationType().getName());
      if (reader != null) {
        readerClassName = reader;
        break;
      }
    }
    if (readerClassName == null) {
      NucleusLogger.METADATA.debug(Localiser.msg("044202", cls.getName()));
      return null;
    }

    AnnotationReader reader = annotationReaders.get(readerClassName);
    if (reader == null) {
      // Try to create this AnnotationReader
      try {
        Class[] ctrArgs = new Class[] {ClassConstants.METADATA_MANAGER};
        Object[] ctrParams = new Object[] {metadataMgr};
        PluginManager pluginMgr = metadataMgr.getNucleusContext().getPluginManager();
        reader =
            (AnnotationReader)
                pluginMgr.createExecutableExtension(
                    "org.datanucleus.annotations",
                    "reader",
                    readerClassName,
                    "reader",
                    ctrArgs,
                    ctrParams);
        annotationReaders.put(
            readerClassName,
            reader); // Save the annotation reader in case we have more of this type
      } catch (Exception e) {
        NucleusLogger.METADATA.warn(
            Localiser.msg("MetaData.AnnotationReaderNotFound", readerClassName));
        return null;
      }
    }

    return reader.getMetaDataForClass(cls, pmd, clr);
  }
  /**
   * Constructor.
   *
   * @param metadataMgr Manager for MetaData
   */
  public AnnotationManagerImpl(MetaDataManager metadataMgr) {
    this.metadataMgr = metadataMgr;

    PluginManager pluginMgr = metadataMgr.getNucleusContext().getPluginManager();

    // Load up the registry of available annotation readers
    ConfigurationElement[] elems =
        pluginMgr.getConfigurationElementsForExtension("org.datanucleus.annotations", null, null);
    if (elems != null) {
      for (int i = 0; i < elems.length; i++) {
        annotationReaderLookup.put(
            elems[i].getAttribute("annotation-class"), elems[i].getAttribute("reader"));
      }
    }

    // Load up the registry of available class annotation handlers
    elems =
        pluginMgr.getConfigurationElementsForExtension(
            "org.datanucleus.class_annotation_handler", null, null);
    if (elems != null && elems.length > 0) {
      classAnnotationHandlerAnnotations = new HashSet<String>(elems.length);
      classAnnotationHandlers = new HashMap<String, ClassAnnotationHandler>(elems.length);
      for (int i = 0; i < elems.length; i++) {
        classAnnotationHandlerAnnotations.add(elems[i].getAttribute("annotation-class"));
      }
    }

    // Load up the registry of available member annotation handlers
    elems =
        pluginMgr.getConfigurationElementsForExtension(
            "org.datanucleus.member_annotation_handler", null, null);
    if (elems != null && elems.length > 0) {
      memberAnnotationHandlerAnnotations = new HashSet<String>(elems.length);
      memberAnnotationHandlers = new HashMap<String, MemberAnnotationHandler>(elems.length);
      for (int i = 0; i < elems.length; i++) {
        memberAnnotationHandlerAnnotations.add(elems[i].getAttribute("annotation-class"));
      }
    }
  }