private List<ComponentDeclaration> getDeclaredComponents(File jarFile) throws IOException {
    ZipInputStream zis = new ZipInputStream(new FileInputStream(jarFile));

    List<ComponentDeclaration> componentDeclarations = null;
    List<ComponentDeclaration> componentOverrideDeclarations = null;

    try {
      for (ZipEntry entry = zis.getNextEntry();
          entry != null && (componentDeclarations == null || componentOverrideDeclarations == null);
          entry = zis.getNextEntry()) {
        if (entry.getName().equals(ComponentAnnotationLoader.COMPONENT_LIST)) {
          componentDeclarations = this.jarLoader.getDeclaredComponents(zis);
        } else if (entry.getName().equals(ComponentAnnotationLoader.COMPONENT_OVERRIDE_LIST)) {
          componentOverrideDeclarations = this.jarLoader.getDeclaredComponents(zis);
        }
      }
    } finally {
      zis.close();
    }

    // Merge all overrides found with a priority of 0. This is purely for backward compatibility
    // since the
    // override files is now deprecated.
    if (componentOverrideDeclarations != null) {
      if (componentDeclarations == null) {
        componentDeclarations = new ArrayList<ComponentDeclaration>();
      }
      for (ComponentDeclaration componentOverrideDeclaration : componentOverrideDeclarations) {
        componentDeclarations.add(
            new ComponentDeclaration(componentOverrideDeclaration.getImplementationClassName(), 0));
      }
    }

    return componentDeclarations;
  }
  private void unloadComponents(File jarFile, ExtensionURLClassLoader classLoader)
      throws UninstallException {
    try {
      List<ComponentDeclaration> componentDeclarations = getDeclaredComponents(jarFile);

      if (componentDeclarations == null) {
        this.logger.debug("[{}] does not contain any component", jarFile);
        return;
      }

      for (ComponentDeclaration componentDeclaration : componentDeclarations) {
        try {
          for (ComponentDescriptor componentDescriptor :
              this.jarLoader.getComponentsDescriptors(
                  classLoader.loadClass(componentDeclaration.getImplementationClassName()))) {
            this.componentManager.unregisterComponent(
                componentDescriptor.getRole(), componentDescriptor.getRoleHint());
          }
        } catch (ClassNotFoundException e) {
          this.logger.error(
              "Failed to load class [{}]", componentDeclaration.getImplementationClassName(), e);
        }
      }
    } catch (Exception e) {
      throw new UninstallException("Failed to load jar file components", e);
    }
  }
  /**
   * Loads all components defined using annotations.
   *
   * @param manager the component manager to use to dynamically register components
   * @param classLoader the classloader to use to look for the Component list declaration file (
   *     {@code META-INF/components.txt})
   */
  public void initialize(ComponentManager manager, ClassLoader classLoader) {
    try {
      // Find all declared components by retrieving the list defined in COMPONENT_LIST.
      List<ComponentDeclaration> componentDeclarations =
          getDeclaredComponents(classLoader, COMPONENT_LIST);

      // Find all the Component overrides and adds them to the bottom of the list as component
      // declarations with
      // the highest priority of 0. This is purely for backward compatibility since the override
      // files is now
      // deprecated.
      List<ComponentDeclaration> componentOverrideDeclarations =
          getDeclaredComponents(classLoader, COMPONENT_OVERRIDE_LIST);
      for (ComponentDeclaration componentOverrideDeclaration : componentOverrideDeclarations) {
        // Since the old way to declare an override was to define it in both a component.txt and a
        // component-overrides.txt file we first need to remove the override component declaration
        // stored in
        // componentDeclarations.
        componentDeclarations.remove(componentOverrideDeclaration);
        // Add it to the end of the list with the highest priority.
        componentDeclarations.add(
            new ComponentDeclaration(componentOverrideDeclaration.getImplementationClassName(), 0));
      }

      initialize(manager, classLoader, componentDeclarations);
    } catch (Exception e) {
      // Make sure we make the calling code fail in order to fail fast and prevent the application
      // to start
      // if something is amiss.
      throw new RuntimeException("Failed to get the list of components to load", e);
    }
  }
  /**
   * @param manager the component manager to use to dynamically register components
   * @param classLoader the classloader to use to look for the Component list declaration file (
   *     {@code META-INF/components.txt})
   * @param componentDeclarations the declarations of components to register
   * @since 4.0M1
   */
  public void unregister(
      ComponentManager manager,
      ClassLoader classLoader,
      List<ComponentDeclaration> componentDeclarations) {
    for (ComponentDeclaration componentDeclaration : componentDeclarations) {
      try {
        for (ComponentDescriptor<?> componentDescriptor :
            getComponentsDescriptors(
                classLoader.loadClass(componentDeclaration.getImplementationClassName()))) {
          manager.unregisterComponent(componentDescriptor);

          if (componentDescriptor.getRoleType() instanceof ParameterizedType) {
            Class roleClass = ReflectionUtils.getTypeClass(componentDescriptor.getRoleType());

            DefaultComponentDescriptor<?> classComponentDescriptor =
                new DefaultComponentDescriptor(componentDescriptor);
            classComponentDescriptor.setRoleType(roleClass);

            manager.unregisterComponent(classComponentDescriptor);
          }
        }
      } catch (ClassNotFoundException e) {
        getLogger()
            .warn(
                "Can't find any existing component with class [{}]. Ignoring it.",
                componentDeclaration.getImplementationClassName());
      }
    }
  }
  /**
   * @param manager the component manager to use to dynamically register components
   * @param classLoader the classloader to use to look for the Component list declaration file (
   *     {@code META-INF/components.txt})
   * @param componentDeclarations the declarations of components to register
   * @since 4.0M1
   */
  public void register(
      ComponentManager manager,
      ClassLoader classLoader,
      List<ComponentDeclaration> componentDeclarations) {
    try {
      // 2) For each component class name found, load its class and use introspection to find the
      // necessary
      // annotations required to create a Component Descriptor.
      Map<RoleHint<?>, ComponentDescriptor<?>> descriptorMap =
          new HashMap<RoleHint<?>, ComponentDescriptor<?>>();
      Map<RoleHint<?>, Integer> priorityMap = new HashMap<RoleHint<?>, Integer>();

      for (ComponentDeclaration componentDeclaration : componentDeclarations) {
        Class<?> componentClass =
            classLoader.loadClass(componentDeclaration.getImplementationClassName());

        // Look for ComponentRole annotations and register one component per ComponentRole found
        for (Type componentRoleType : findComponentRoleTypes(componentClass)) {
          for (ComponentDescriptor<?> componentDescriptor :
              this.factory.createComponentDescriptors(componentClass, componentRoleType)) {
            // If there's already a existing role/hint in the list of descriptors then decide which
            // one
            // to keep by looking at their priorities. Highest priority wins (i.e. lowest integer
            // value).
            RoleHint<?> roleHint =
                new RoleHint(componentDescriptor.getRoleType(), componentDescriptor.getRoleHint());

            addComponent(
                descriptorMap,
                priorityMap,
                roleHint,
                componentDescriptor,
                componentDeclaration,
                true);
          }
        }
      }

      // 3) Activate all component descriptors
      for (ComponentDescriptor<?> descriptor : descriptorMap.values()) {
        manager.registerComponent(descriptor);
      }
    } catch (Exception e) {
      // Make sure we make the calling code fail in order to fail fast and prevent the application
      // to start
      // if something is amiss.
      throw new RuntimeException("Failed to dynamically load components with annotations", e);
    }
  }
 @Override
 public boolean equals(Object object) {
   if (object == null) {
     return false;
   }
   if (object == this) {
     return true;
   }
   if (object.getClass() != getClass()) {
     return false;
   }
   ComponentDeclaration rhs = (ComponentDeclaration) object;
   return new EqualsBuilder()
       .append(getImplementationClassName(), rhs.getImplementationClassName())
       .append(getPriority(), rhs.getPriority())
       .isEquals();
 }
 private void addComponent(
     Map<RoleHint<?>, ComponentDescriptor<?>> descriptorMap,
     Map<RoleHint<?>, Integer> priorityMap,
     RoleHint<?> roleHint,
     ComponentDescriptor<?> componentDescriptor,
     ComponentDeclaration componentDeclaration,
     boolean warn) {
   if (descriptorMap.containsKey(roleHint)) {
     // Compare priorities
     int currentPriority = priorityMap.get(roleHint);
     if (componentDeclaration.getPriority() < currentPriority) {
       // Override!
       descriptorMap.put(roleHint, componentDescriptor);
       priorityMap.put(roleHint, componentDeclaration.getPriority());
     } else if (componentDeclaration.getPriority() == currentPriority) {
       if (warn) {
         // Warning that we're not overwriting since they have the same priorities
         getLogger()
             .warn(
                 "Component [{}] which implements [{}] tried to overwrite component "
                     + "[{}]. However, no action was taken since both components have the same priority "
                     + "level of [{}].",
                 new Object[] {
                   componentDeclaration.getImplementationClassName(),
                   roleHint,
                   descriptorMap.get(roleHint).getImplementation().getName(),
                   currentPriority
                 });
       }
     } else {
       getLogger()
           .debug(
               "Ignored component [{}] since its priority level of [{}] is lower "
                   + "than the currently registered component [{}] which has a priority of [{}]",
               new Object[] {
                 componentDeclaration.getImplementationClassName(),
                 componentDeclaration.getPriority(),
                 currentPriority
               });
     }
   } else {
     descriptorMap.put(roleHint, componentDescriptor);
     priorityMap.put(roleHint, componentDeclaration.getPriority());
   }
 }