private CategoryEvent updateCategory(Category category) {
    Set categoryActivityBindings = (Set) categoryActivityBindingsByCategoryId.get(category.getId());
    boolean categoryActivityBindingsChanged =
        category.setCategoryActivityBindings(
            categoryActivityBindings != null ? categoryActivityBindings : Collections.EMPTY_SET);
    CategoryDefinition categoryDefinition =
        (CategoryDefinition) categoryDefinitionsById.get(category.getId());
    boolean definedChanged = category.setDefined(categoryDefinition != null);
    boolean nameChanged =
        category.setName(categoryDefinition != null ? categoryDefinition.getName() : null);
    boolean descriptionChanged =
        category.setDescription(
            categoryDefinition != null ? categoryDefinition.getDescription() : null);

    if (categoryActivityBindingsChanged || definedChanged || nameChanged || descriptionChanged) {
      return new CategoryEvent(
          category,
          categoryActivityBindingsChanged,
          definedChanged,
          descriptionChanged,
          nameChanged);
    }

    return null;
  }
  private void readRegistry(boolean setDefaults) {
    if (!isRegexpSupported()) {
      return;
    }
    Collection activityDefinitions = new ArrayList();
    activityDefinitions.addAll(activityRegistry.getActivityDefinitions());
    Map activityDefinitionsById =
        new HashMap(ActivityDefinition.activityDefinitionsById(activityDefinitions, false));

    for (Iterator iterator = activityDefinitionsById.values().iterator(); iterator.hasNext(); ) {
      ActivityDefinition activityDefinition = (ActivityDefinition) iterator.next();
      String name = activityDefinition.getName();

      if (name == null || name.length() == 0) {
        iterator.remove();
      }
    }

    Collection categoryDefinitions = new ArrayList();
    categoryDefinitions.addAll(activityRegistry.getCategoryDefinitions());
    Map categoryDefinitionsById =
        new HashMap(CategoryDefinition.categoryDefinitionsById(categoryDefinitions, false));

    for (Iterator iterator = categoryDefinitionsById.values().iterator(); iterator.hasNext(); ) {
      CategoryDefinition categoryDefinition = (CategoryDefinition) iterator.next();
      String name = categoryDefinition.getName();

      if (name == null || name.length() == 0) {
        iterator.remove();
      }
    }

    Map activityRequirementBindingDefinitionsByActivityId =
        ActivityRequirementBindingDefinition.activityRequirementBindingDefinitionsByActivityId(
            activityRegistry.getActivityRequirementBindingDefinitions());
    Map activityRequirementBindingsByActivityId = new HashMap();

    for (Iterator iterator =
            activityRequirementBindingDefinitionsByActivityId.entrySet().iterator();
        iterator.hasNext(); ) {
      Map.Entry entry = (Map.Entry) iterator.next();
      String parentActivityId = (String) entry.getKey();

      if (activityDefinitionsById.containsKey(parentActivityId)) {
        Collection activityRequirementBindingDefinitions = (Collection) entry.getValue();

        if (activityRequirementBindingDefinitions != null) {
          for (Iterator iterator2 = activityRequirementBindingDefinitions.iterator();
              iterator2.hasNext(); ) {
            ActivityRequirementBindingDefinition activityRequirementBindingDefinition =
                (ActivityRequirementBindingDefinition) iterator2.next();
            String childActivityId = activityRequirementBindingDefinition.getRequiredActivityId();

            if (activityDefinitionsById.containsKey(childActivityId)) {
              IActivityRequirementBinding activityRequirementBinding =
                  new ActivityRequirementBinding(childActivityId, parentActivityId);
              Set activityRequirementBindings =
                  (Set) activityRequirementBindingsByActivityId.get(parentActivityId);

              if (activityRequirementBindings == null) {
                activityRequirementBindings = new HashSet();
                activityRequirementBindingsByActivityId.put(
                    parentActivityId, activityRequirementBindings);
              }

              activityRequirementBindings.add(activityRequirementBinding);
            }
          }
        }
      }
    }

    Map activityPatternBindingDefinitionsByActivityId =
        ActivityPatternBindingDefinition.activityPatternBindingDefinitionsByActivityId(
            activityRegistry.getActivityPatternBindingDefinitions());
    Map activityPatternBindingsByActivityId = new HashMap();

    for (Iterator iterator = activityPatternBindingDefinitionsByActivityId.entrySet().iterator();
        iterator.hasNext(); ) {
      Map.Entry entry = (Map.Entry) iterator.next();
      String activityId = (String) entry.getKey();

      if (activityDefinitionsById.containsKey(activityId)) {
        Collection activityPatternBindingDefinitions = (Collection) entry.getValue();

        if (activityPatternBindingDefinitions != null) {
          for (Iterator iterator2 = activityPatternBindingDefinitions.iterator();
              iterator2.hasNext(); ) {
            ActivityPatternBindingDefinition activityPatternBindingDefinition =
                (ActivityPatternBindingDefinition) iterator2.next();
            String pattern = activityPatternBindingDefinition.getPattern();

            if (pattern != null && pattern.length() != 0) {
              IActivityPatternBinding activityPatternBinding =
                  new ActivityPatternBinding(activityId, pattern);
              Set activityPatternBindings =
                  (Set) activityPatternBindingsByActivityId.get(activityId);

              if (activityPatternBindings == null) {
                activityPatternBindings = new HashSet();
                activityPatternBindingsByActivityId.put(activityId, activityPatternBindings);
              }

              activityPatternBindings.add(activityPatternBinding);
            }
          }
        }
      }
    }

    Map categoryActivityBindingDefinitionsByCategoryId =
        CategoryActivityBindingDefinition.categoryActivityBindingDefinitionsByCategoryId(
            activityRegistry.getCategoryActivityBindingDefinitions());
    Map categoryActivityBindingsByCategoryId = new HashMap();

    for (Iterator iterator = categoryActivityBindingDefinitionsByCategoryId.entrySet().iterator();
        iterator.hasNext(); ) {
      Map.Entry entry = (Map.Entry) iterator.next();
      String categoryId = (String) entry.getKey();

      if (categoryDefinitionsById.containsKey(categoryId)) {
        Collection categoryActivityBindingDefinitions = (Collection) entry.getValue();

        if (categoryActivityBindingDefinitions != null) {
          for (Iterator iterator2 = categoryActivityBindingDefinitions.iterator();
              iterator2.hasNext(); ) {
            CategoryActivityBindingDefinition categoryActivityBindingDefinition =
                (CategoryActivityBindingDefinition) iterator2.next();
            String activityId = categoryActivityBindingDefinition.getActivityId();

            if (activityDefinitionsById.containsKey(activityId)) {
              ICategoryActivityBinding categoryActivityBinding =
                  new CategoryActivityBinding(activityId, categoryId);
              Set categoryActivityBindings =
                  (Set) categoryActivityBindingsByCategoryId.get(categoryId);

              if (categoryActivityBindings == null) {
                categoryActivityBindings = new HashSet();
                categoryActivityBindingsByCategoryId.put(categoryId, categoryActivityBindings);
              }

              categoryActivityBindings.add(categoryActivityBinding);
            }
          }
        }
      }
    }

    this.activityRequirementBindingsByActivityId = activityRequirementBindingsByActivityId;
    this.activityDefinitionsById = activityDefinitionsById;
    this.activityPatternBindingsByActivityId = activityPatternBindingsByActivityId;
    this.categoryActivityBindingsByCategoryId = categoryActivityBindingsByCategoryId;
    this.categoryDefinitionsById = categoryDefinitionsById;
    boolean definedActivityIdsChanged = false;
    Set definedActivityIds = new HashSet(activityDefinitionsById.keySet());

    Set previouslyDefinedActivityIds = null;
    if (!definedActivityIds.equals(this.definedActivityIds)) {
      previouslyDefinedActivityIds = this.definedActivityIds;
      this.definedActivityIds = definedActivityIds;
      definedActivityIdsChanged = true;
    }

    boolean definedCategoryIdsChanged = false;
    Set definedCategoryIds = new HashSet(categoryDefinitionsById.keySet());

    Set previouslyDefinedCategoryIds = null;
    if (!definedCategoryIds.equals(this.definedCategoryIds)) {
      previouslyDefinedCategoryIds = this.definedCategoryIds;
      this.definedCategoryIds = definedCategoryIds;
      definedCategoryIdsChanged = true;
    }

    Set enabledActivityIds = new HashSet(this.enabledActivityIds);
    getRequiredActivityIds(this.enabledActivityIds, enabledActivityIds);
    boolean enabledActivityIdsChanged = false;

    Set previouslyEnabledActivityIds = null;
    if (!this.enabledActivityIds.equals(enabledActivityIds)) {
      previouslyEnabledActivityIds = this.enabledActivityIds;
      this.enabledActivityIds = enabledActivityIds;
      enabledActivityIdsChanged = true;
    }

    Map activityEventsByActivityId = updateActivities(activitiesById.keySet());

    Map categoryEventsByCategoryId = updateCategories(categoriesById.keySet());

    Map identifierEventsByIdentifierId = updateIdentifiers(identifiersById.keySet());

    if (definedActivityIdsChanged || definedCategoryIdsChanged || enabledActivityIdsChanged) {
      fireActivityManagerChanged(
          new ActivityManagerEvent(
              this,
              definedActivityIdsChanged,
              definedCategoryIdsChanged,
              enabledActivityIdsChanged,
              previouslyDefinedActivityIds,
              previouslyDefinedCategoryIds,
              previouslyEnabledActivityIds));
    }

    if (activityEventsByActivityId != null) {
      notifyActivities(activityEventsByActivityId);
    }

    if (categoryEventsByCategoryId != null) {
      notifyCategories(categoryEventsByCategoryId);
    }

    if (identifierEventsByIdentifierId != null) {
      notifyIdentifiers(identifierEventsByIdentifierId);
    }

    if (setDefaults) {
      setEnabledActivityIds(new HashSet(activityRegistry.getDefaultEnabledActivities()));
    }
  }
  @Override
  public void generate(final GenerationContext context) throws Exception {
    Document doc;
    try (BufferedInputStream is =
        new BufferedInputStream(Files.newInputStream(context.getFile()))) {
      doc = this.xml.parse(is);
    }

    final CategoryDefinition def = CategoryXmlParser.parse(doc);

    final String baseName = context.getArtifactInformation().getName();

    final Map<String, Set<ArtifactInformation>> map = new HashMap<>();

    for (final ArtifactInformation ai : context.getChannelArtifacts()) {
      if (Helper.isBundle(ai.getMetaData())) {
        final String id = ai.getMetaData().get(MK_OSGI_NAME);
        final Set<String> cats = def.getBundles().get(id);
        if (cats != null) {
          for (final String cat : cats) {
            addMap(map, cat, ai);
          }
        }
      }

      if (Helper.isFeature(ai.getMetaData())) {
        final String id = ai.getMetaData().get(MK_OSGI_NAME);
        final Set<String> cats = def.getFeatures().get(id);
        if (cats != null) {
          for (final String cat : cats) {
            addMap(map, cat, ai);
          }
        }
      }
    }

    context.createVirtualArtifact(
        baseName + "-p2metadata.xml",
        out -> {
          Helper.createFragmentFile(
              out,
              (units) -> {
                for (final Category cat : def.getCategories()) {
                  Helper.createCategoryUnit(
                      units,
                      cat.getId(),
                      cat.getLabel(),
                      cat.getDescription(),
                      Helper.makeDefaultVersion(),
                      (unit) -> {
                        final Element reqs = XmlHelper.addElement(unit, "requires");

                        final Set<String> ctx = new HashSet<>();

                        final Set<ArtifactInformation> list = map.get(cat.getId());
                        if (list != null) {
                          for (final ArtifactInformation ai : list) {
                            if (Helper.isFeature(ai.getMetaData())) {
                              Helper.addFeatureRequirement(ctx, reqs, ai);
                            } else if (Helper.isBundle(ai.getMetaData())) {
                              Helper.addBundleRequirement(ctx, reqs, ai);
                            }
                          }
                        }
                        XmlHelper.fixSize(reqs);
                      });
                }
              });
        },
        null);
  }