/**
  * Returns {@code true} if the given key has already been registered. This is used to prevent
  * reentrant metadata registration (and cycles).
  */
 public boolean isRegistered(ElementKey<?, ?> key) {
   RootKey rootKey = Schema.getRootKey(key);
   ElementMetadataRegistryBuilder elementRegistry = elements.get(rootKey);
   if (elementRegistry != null) {
     return elementRegistry.isRegistered(null, key, null);
   }
   return false;
 }
  /**
   * Here is what we do to deal with whitelisted children: 1) Find each transform(parent, child,
   * context)-> whitelisted children 2) Find composite(parent, child, context)-> all children. 3)
   * For each child element not in the whitelist -> hide the child element.
   */
  private void whitelistElements() {

    for (Map.Entry<RootKey, ElementMetadataRegistryBuilder> rootEntry : elements.entrySet()) {
      ElementMetadataRegistryBuilder builder = rootEntry.getValue();
      Map<TransformKey, Set<ElementKey<?, ?>>> whitelistMap = Maps.newLinkedHashMap();

      Map<TransformKey, ElementCreatorImpl> creators = builder.getCreators();

      for (Map.Entry<TransformKey, ElementCreatorImpl> entry : creators.entrySet()) {
        TransformKey key = entry.getKey();
        ElementCreatorImpl element = entry.getValue();
        if (element.getElementWhitelist() != null) {
          whitelistMap.put(key, element.getElementWhitelist());
        }
      }

      for (Map.Entry<TransformKey, Set<ElementKey<?, ?>>> whitelistEntry :
          whitelistMap.entrySet()) {
        TransformKey key = whitelistEntry.getKey();
        Set<ElementKey<?, ?>> whitelist = whitelistEntry.getValue();
        Set<QName> whitelistNames = Sets.newHashSet();
        for (ElementKey<?, ?> whitelistKey : whitelist) {
          whitelistNames.add(whitelistKey.getId());
        }

        Set<ElementKey<?, ?>> allChildren = Sets.newHashSet();
        for (Map.Entry<TransformKey, ElementCreatorImpl> entry : creators.entrySet()) {

          if (entry.getKey().matches(key)) {
            allChildren.addAll(entry.getValue().getElementSet());
          }
        }

        if (!allChildren.containsAll(whitelist)) {
          Set<ElementKey<?, ?>> missing = Sets.newHashSet(whitelist);
          missing.removeAll(allChildren);
          throw new IllegalStateException(
              "Missing children!  Whitelist specified "
                  + missing
                  + " but did not find those child elements.");
        }

        for (ElementKey<?, ?> child : allChildren) {
          if (!whitelistNames.contains(child.getId())) {
            ElementKey<?, ?> parent = (ElementKey<?, ?>) key.getKey();
            build(parent, child, key.getContext()).setVisible(false);
          }
        }
      }
    }
  }
 /**
  * Merges another metadata registry into this metadata registry. Both registries are locked during
  * this time, first this registry and then the other registry. Do not attempt to do a.merge(b) and
  * b.merge(a) in separate threads at the same time or a deadlock may occur.
  */
 public synchronized MetadataRegistry merge(MetadataRegistry other) {
   synchronized (other) {
     for (Map.Entry<RootKey, AttributeMetadataRegistryBuilder> entry :
         other.attributes.entrySet()) {
       RootKey key = entry.getKey();
       AttributeMetadataRegistryBuilder builder = attributes.get(key);
       if (builder == null) {
         builder = new AttributeMetadataRegistryBuilder(this);
         attributes.put(key, builder);
       }
       builder.merge(entry.getValue());
     }
     for (Map.Entry<RootKey, ElementMetadataRegistryBuilder> entry : other.elements.entrySet()) {
       RootKey key = entry.getKey();
       ElementMetadataRegistryBuilder builder = elements.get(key);
       if (builder == null) {
         builder = new ElementMetadataRegistryBuilder(this);
         elements.put(key, builder);
       }
       builder.merge(entry.getValue());
     }
   }
   return this;
 }