gt:             this.tags = Collections.unmodifiableSet(new HashSet<>(tags));
context: package org.jboss.windup.config.metadata;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;
  import java.util.logging.Logger;
  
  import org.apache.commons.lang3.StringUtils;
  import org.jboss.forge.furnace.addons.Addon;
  import org.jboss.forge.furnace.addons.AddonId;
  import org.jboss.forge.furnace.util.Annotations;
  import org.jboss.forge.furnace.util.Assert;
  import org.jboss.forge.furnace.versions.EmptyVersionRange;
  import org.jboss.forge.furnace.versions.Versions;
  import org.jboss.windup.config.RuleProvider;
  import org.jboss.windup.config.loader.RuleProviderLoader;
  import org.jboss.windup.config.phase.MigrationRulesPhase;
  import org.jboss.windup.config.phase.RulePhase;
  import org.jboss.windup.util.Logging;
  import org.ocpsoft.rewrite.config.Rule;
  
  /**
   * Fluent builder for creating {@link RuleProviderMetadata} instances. Provides sensible defaults using given required values.
   * <p>
   * If {@link RulesetMetadata} is available in the {@link Addon} in which this {@link MetadataBuilder} was constructed, this will inherit values from
   * {@link RulesetMetadata} for {@link #getTags()}, {@link #getSourceTechnologies()}, {@link #getTargetTechnologies()} and {@link #getRequiredAddons()}.
   * <p>
   * Inherited metadata is specified by {@link #setRulesetMetadata(RulesetMetadata)}, and is typically performed by the {@link RuleProviderLoader}
   * implementation.
   *
   * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
   */
  public class MetadataBuilder extends AbstractRulesetMetadata implements RuleProviderMetadata
  {
      private static final Logger LOG = Logging.get(MetadataBuilder.class);
      public static final Class<? extends RulePhase> DEFAULT_PHASE = MigrationRulesPhase.class;
  
      private Class<? extends RuleProvider> implementationType;
      private String origin;
      private Class<? extends RulePhase> phase;
  
      private List<Class<? extends RuleProvider>> executeAfter = new ArrayList<>();
      private List<String> executeAfterIDs = new ArrayList<>();
      private List<Class<? extends RuleProvider>> executeBefore = new ArrayList<>();
      private List<String> executeBeforeIDs = new ArrayList<>();
      private String description;
      private Set<String> tags = new HashSet<>();
      private final Set<TechnologyReference> sourceTechnologies = new HashSet<>();
      private final Set<TechnologyReference> targetTechnologies = new HashSet<>();
      private final Set<AddonId> requiredAddons = new HashSet<>();
      private boolean haltOnException = false;
      private boolean overrideProvider = false;
      private boolean disabled = false;
  
      private RulesetMetadata parent = new AbstractRulesetMetadata("NULL");
  
      private MetadataBuilder(Class<? extends RuleProvider> implementationType, String providerId)
      {
          super(providerId);
          this.implementationType = implementationType;
      }
  
      /**
       * Create a new {@link RuleProviderMetadata} builder instance for the given {@link RuleProvider} type, using the provided parameters and
       * {@link RulesetMetadata} to seed sensible defaults.
       */
      public static MetadataBuilder forProvider(Class<? extends RuleProvider> implementationType)
      {
          String id = implementationType.getSimpleName();
  
          RuleMetadata metadata = Annotations.getAnnotation(implementationType, RuleMetadata.class);
          if (metadata != null && !metadata.id().isEmpty())
              id = metadata.id();
  
          return forProvider(implementationType, id);
      }
  
      /**
       * Create a new {@link RuleProviderMetadata} builder instance for the given {@link RuleProvider} type, and {@link String} ID, using the provided
       * parameters and {@link RulesetMetadata} to seed sensible defaults.
       */
      public static MetadataBuilder forProvider(Class<? extends RuleProvider> implementationType, String providerId)
      {
          Assert.notNull(implementationType, "Rule provider Implementation type must not be null.");
          Assert.notNull(providerId, "Rule provider ID must not be null.");
  
          MetadataBuilder builder = new MetadataBuilder(implementationType, providerId)
                      .setOrigin(implementationType.getName() + " loaded from " + implementationType.getClassLoader().toString());
  
          RuleMetadata metadata = Annotations.getAnnotation(implementationType, RuleMetadata.class);
          if (metadata == null)
              return builder;
  
          builder.setOverrideProvider(metadata.overrideProvider());
  
          if (StringUtils.isNotBlank(metadata.description()))
              builder.setDescription(metadata.description());
  
          Class<? extends RuleProvider>[] after = metadata.after();
          if (after.length > 0)
              builder.setExecuteAfter(Arrays.asList(after));
  
          String[] afterIDs = metadata.afterIDs();
          if (afterIDs.length > 0)
              builder.setExecuteAfterIDs(Arrays.asList(afterIDs));
  
          Class<? extends RuleProvider>[] before = metadata.before();
          if (before.length > 0)
              builder.setExecuteBefore(Arrays.asList(before));
  
          String[] beforeIDs = metadata.beforeIDs();
          if (beforeIDs.length > 0)
              builder.setExecuteBeforeIDs(Arrays.asList(beforeIDs));
  
          builder.setPhase(metadata.phase());
  
          String[] tags = metadata.tags();
          if (tags.length > 0)
              builder.setTags(Arrays.asList(tags));
  
          Technology[] sourceTechnologies = metadata.sourceTechnologies();
          if (sourceTechnologies.length > 0)
          {
              for (Technology technology : sourceTechnologies)
              {
                  builder.addSourceTechnology(new TechnologyReference(
                              technology.id(),
                              "".equals(technology.versionRange().trim())
                                      ? new EmptyVersionRange()
                                      : Versions.parseVersionRange(technology.versionRange())));
              }
          }
  
          Technology[] targetTechnologies = metadata.targetTechnologies();
          if (targetTechnologies.length > 0)
          {
              for (Technology technology : targetTechnologies)
              {
                  builder.addTargetTechnology(new TechnologyReference(
                              technology.id(),
                              "".equals(technology.versionRange().trim())
                                      ? new EmptyVersionRange()
                                      : Versions.parseVersionRange(technology.versionRange())));
              }
          }
  
          builder.haltOnException = metadata.haltOnException();
          builder.disabled = metadata.disabled();
          if (builder.disabled)
              LOG.info("Disabled provider: " + providerId);
  
          return builder;
      }
  
      @Override
      public boolean equals(Object o)
      {
          if (this == o) return true;
          if (!(o instanceof MetadataBuilder)) return false;
          if (!super.equals(o)) return false;
  
          MetadataBuilder that = (MetadataBuilder) o;
  
          return overrideProvider == that.overrideProvider;
  
      }
  
      @Override
      public int hashCode()
      {
          int result = super.hashCode();
          result = 31 * result + (overrideProvider ? 1 : 0);
          return result;
      }
  
      @Override
      public Class<? extends RuleProvider> getType()
      {
          return implementationType;
      }
  
      @Override
      public RulesetMetadata getRulesetMetadata()
      {
          return parent;
      }
  
      public MetadataBuilder setRulesetMetadata(RulesetMetadata parent)
      {
          if (parent != null)
              this.parent = parent;
  
          return this;
      }
  
      @Override
      public boolean isOverrideProvider()
      {
          return overrideProvider;
      }
  
      /**
       * Sets whether or not this provider's rules should override rules from other providers
       * with the same ID.
       */
      public MetadataBuilder setOverrideProvider(boolean overrideProvider)
      {
          this.overrideProvider = overrideProvider;
          return this;
      }
  
      @Override
      public String getOrigin()
      {
          return origin == null ? super.getOrigin() : origin;
      }
  
      /**
       * Set the descriptive information indicating where the corresponding {@link RuleProvider} instance is located (eg, a path to an XML file on disk,
       * or an {@link Addon} coordinate and class name).
       */
      public MetadataBuilder setOrigin(String origin)
      {
          this.origin = origin;
          return this;
      }
  
      @Override
      public Class<? extends RulePhase> getPhase()
      {
          return phase == null ? DEFAULT_PHASE : phase;
      }
  
      /**
       * Set the {@link RulePhase} in which the {@link Rule} instances from the corresponding {@link RuleProvider} instance should be executed.
       * <p>
       * The default phase is {@link org.jboss.windup.config.phase.MigrationRulesPhase}.
       */
      public MetadataBuilder setPhase(Class<? extends RulePhase> phase)
      {
          this.phase = phase;
          return this;
      }
  
      @Override
      public List<Class<? extends RuleProvider>> getExecuteAfter()
      {
          return Collections.unmodifiableList(executeAfter);
      }
  
      /**
       * Set the list of {@link RuleProvider} classes that should execute before the {@link Rule} instances in the corresponding {@link RuleProvider}
       * instance.
       *
       * <p>
       * {@link RuleProvider} references can also be specified based on id ({@link #getExecuteAfterIDs}).
       */
      public MetadataBuilder setExecuteAfter(List<Class<? extends RuleProvider>> executeAfter)
      {
          this.executeAfter = new ArrayList<>(executeAfter);
          return this;
      }
  
      /**
       * Ad an entry to the list of {@link RuleProvider} classes that should execute after the {@link Rule} instances in the corresponding
       * {@link RuleProvider} instance.
       *
       * {@link RuleProvider}s can also be specified based on id ({@link #getExecuteBeforeIDs}).
       */
      public MetadataBuilder addExecuteAfter(Class<? extends RuleProvider> type)
      {
          if (type != null)
          {
              executeAfter.add(type);
          }
          return this;
      }
  
      /**
       * Sets the human readable description.
       */
      public MetadataBuilder setDescription(String description)
      {
          this.description = description;
          return this;
      }
  
      @Override
      public String getDescription()
      {
          return this.description;
      }
  
      @Override
      public List<String> getExecuteAfterIDs()
      {
          return Collections.unmodifiableList(executeAfterIDs);
      }
  
      /**
       * Set the list of the {@link RuleProvider} classes that should execute before the {@link Rule} instances in the corresponding
       * {@link RuleProvider} instance.
       *
       * <p>
       * This is returned as a list of Rule IDs in order to support extensions that cannot depend on each other via class names. For example, in the
       * case of the Groovy rules extension, a single class covers many rules with their own IDs.
       *
       * For specifying Java-based rules, {@link #getExecuteAfter()} is preferred.
       */
      public MetadataBuilder setExecuteAfterIDs(List<String> executeAfterIDs)
      {
          this.executeAfterIDs = new ArrayList<>(executeAfterIDs);
          return this;
      }
  
      /**
       * Add an entry to the list of the {@link RuleProvider} classes that should execute before the {@link Rule} instances in the corresponding
       * {@link RuleProvider} instance.
       *
       * <p>
       * This is returned as a list of Rule IDs in order to support extensions that cannot depend on each other via class names. For example, in the
       * case of the Groovy rules extension, a single class covers many rules with their own IDs.
       *
       * For specifying Java-based rules, {@link #getExecuteAfter()} is preferred.
       */
      public MetadataBuilder addExecuteAfterId(String id)
      {
          if (id != null)
          {
              executeAfterIDs.add(id);
          }
          return this;
      }
  
      @Override
      public List<Class<? extends RuleProvider>> getExecuteBefore()
      {
          return Collections.unmodifiableList(executeBefore);
      }
  
      /**
       * Set the list of {@link RuleProvider} classes that should execute after the {@link Rule} instances in the corresponding {@link RuleProvider}
       * instance.
       *
       * {@link RuleProvider}s can also be specified based on id ({@link #getExecuteBeforeIDs}).
       */
      public MetadataBuilder setExecuteBefore(List<Class<? extends RuleProvider>> executeBefore)
      {
          this.executeBefore = new ArrayList<>(executeBefore);
          return this;
      }
  
      /**
       * Ad an entry to the list of {@link RuleProvider} classes that should execute after the {@link Rule} instances in the corresponding
       * {@link RuleProvider} instance.
       *
       * {@link RuleProvider}s can also be specified based on id ({@link #getExecuteBeforeIDs}).
       */
      public MetadataBuilder addExecuteBefore(Class<? extends RuleProvider> type)
      {
          if (type != null)
          {
              executeBefore.add(type);
          }
          return this;
      }
  
      @Override
      public List<String> getExecuteBeforeIDs()
      {
          return Collections.unmodifiableList(executeBeforeIDs);
      }
  
      /**
       * Set the list of the {@link RuleProvider} classes that should execute after the {@link Rule} instances in the corresponding {@link RuleProvider}
       * instance.
       *
       * <p>
       * This is returned as a list of Rule IDs in order to support extensions that cannot depend on each other via class names. For example, in the
       * case of the Groovy rules extension, a single class covers many rules with their own IDs.
       *
       * For specifying Java-based rules, {@link #getExecuteBefore()} is preferred.
       */
      public MetadataBuilder setExecuteBeforeIDs(List<String> executeBeforeIDs)
      {
          this.executeBeforeIDs = new ArrayList<>(executeBeforeIDs);
          return this;
      }
  
      /**
       * Add to the list of the {@link RuleProvider} classes that should execute after the {@link Rule} instances in the corresponding
       * {@link RuleProvider} instance.
       *
       * <p>
       * This is returned as a list of Rule IDs in order to support extensions that cannot depend on each other via class names. For example, in the
       * case of the Groovy rules extension, a single class covers many rules with their own IDs.
       *
       * For specifying Java-based rules, {@link #getExecuteBefore()} is preferred.
       */
      public MetadataBuilder addExecuteBeforeId(String id)
      {
          if (id != null)
          {
              executeBeforeIDs.add(id);
          }
          return this;
      }
  
      /**
       * Add to the {@link Set} of tags by which this {@link RulesetMetadata} is classified.
       * <p>
       * Inherits from {@link RulesetMetadata#getTags()} if available.
       */
      public MetadataBuilder addTags(String tag, String... tags)
      {
          if (!StringUtils.isBlank(tag))
              this.tags.add(tag.trim());
  
          if (tags != null)
          {
              for (String t : tags)
              {
                  if (!StringUtils.isBlank(t))
                      this.tags.add(t.trim());
              }
          }
  
          return this;
      }
  
      public MetadataBuilder addTag(String tag)
      {
          if (!StringUtils.isBlank(tag))
          {
              this.tags.add(tag.trim());
          }
          return this;
      }
  
      @Override
      public Set<String> getTags()
      {
          return join(this.tags, parent.getTags(), super.getTags());
      }
  
      /**
       * Set the tags by which this {@link RulesetMetadata} is classified.
       * <p>
       * Inherits from {@link RulesetMetadata#getTags()} if available.
       */
      public MetadataBuilder setTags(List<String> tags)
      {
          if (tags == null)
              this.tags = new HashSet<>();
          else
  