gt:                         if (!done) {
context: /*
   * JBoss, Home of Professional Open Source.
   * Copyright 2012, Red Hat, Inc., and individual contributors
   * as indicated by the @author tags. See the copyright.txt file in the
   * distribution for a full listing of individual contributors.
   *
   * This is free software; you can redistribute it and/or modify it
   * under the terms of the GNU Lesser General Public License as
   * published by the Free Software Foundation; either version 2.1 of
   * the License, or (at your option) any later version.
   *
   * This software is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this software; if not, write to the Free
   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   */
  
  package org.jboss.as.controller.registry;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashSet;
  import java.util.LinkedHashMap;
  import java.util.LinkedHashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import org.jboss.as.controller.PathAddress;
  import org.jboss.as.controller.PathElement;
  import org.jboss.as.controller.logging.ControllerLogger;
  import org.jboss.dmr.ModelNode;
  
  /**
   * Abstract {@code Resource} implementation.
   *
   * <p>Concurrency note: this class is *not* thread safe</p>
   *
   * @author Emanuel Muckenhuber
   */
  public abstract class AbstractModelResource extends ResourceProvider.ResourceProviderRegistry implements Resource {
  
      /** The children. */
      private final Map<String, ResourceProvider> children = new LinkedHashMap<String, ResourceProvider>();
      private final boolean runtimeOnly;
      private final Set<String> orderedChildTypes;
  
      protected AbstractModelResource() {
          this(false);
      }
  
      protected AbstractModelResource(boolean runtimeOnly) {
          this(runtimeOnly, Collections.emptySet(), true);
      }
  
      protected AbstractModelResource(boolean runtimeOnly, String...orderedChildTypes) {
          this(runtimeOnly, arrayToSet(orderedChildTypes), true);
      }
  
      protected AbstractModelResource(boolean runtimeOnly, Set<String> orderedChildTypes) {
          this(runtimeOnly, orderedChildTypes, false);
      }
  
      AbstractModelResource(boolean runtimeOnly, Set<String> orderedChildTypes, boolean safe) {
          this.runtimeOnly = runtimeOnly;
          this.orderedChildTypes = safe && orderedChildTypes != null
                  ? orderedChildTypes
                  : (orderedChildTypes == null || orderedChildTypes.size() == 0)
                      ? Collections.<String>emptySet()
                      : Collections.unmodifiableSet(new HashSet<>(orderedChildTypes));
      }
  
      private static Set<String> arrayToSet(String[] array) {
          Set<String> set;
          if (array.length == 0) {
              set = Collections.emptySet();
          } else {
              set = new HashSet<String>();
              for (String type : array) {
                  set.add(type);
              }
              set = Collections.unmodifiableSet(set);
          }
          return set;
      }
  
      @Override
      public Resource getChild(final PathElement address) {
          final ResourceProvider provider = getProvider(address.getKey());
          if(provider == null) {
              return null;
          }
          return provider.get(address.getValue());
      }
  
      @Override
      public boolean hasChild(final PathElement address) {
          final ResourceProvider provider = getProvider(address.getKey());
          if(provider == null) {
              return false;
          }
          if(address.isWildcard()) {
              return provider.hasChildren();
          }
          return provider.has(address.getValue());
      }
  
      @Override
      public Resource requireChild(final PathElement address) {
          final Resource resource = getChild(address);
          if(resource == null) {
              throw new NoSuchResourceException(address);
          }
          return resource;
      }
  
      @Override
      public boolean hasChildren(final String childType) {
          final ResourceProvider provider = getProvider(childType);
          return provider != null && provider.hasChildren();
      }
  
      @Override
      public Resource navigate(final PathAddress address) {
          return Tools.navigate(this, address);
      }
  
      @Override
      public Set<String> getChildrenNames(final String childType) {
          final ResourceProvider provider = getProvider(childType);
          if(provider == null) {
              return Collections.emptySet();
          }
          return provider.children();
      }
  
      @Override
      public Set<String> getChildTypes() {
          synchronized (children) {
              return new LinkedHashSet<String>(children.keySet());
          }
      }
  
      @Override
      public Set<ResourceEntry> getChildren(final String childType) {
          final ResourceProvider provider = getProvider(childType);
          if(provider == null) {
              return Collections.emptySet();
          }
          final Set<ResourceEntry> children = new LinkedHashSet<ResourceEntry>();
          for(final String name : provider.children()) {
              final Resource resource = provider.get(name);
              children.add(new DelegateResource(resource) {
                  @Override
                  public String getName() {
                      return name;
                  }
  
                  @Override
                  public PathElement getPathElement() {
                      return PathElement.pathElement(childType, name);
                  }
              });
          }
          return children;
      }
  
      @Override
      public void registerChild(final PathElement address, final Resource resource) {
          if(address.isMultiTarget()) {
              throw new IllegalArgumentException();
          }
          getOrCreateProvider(address.getKey()).register(address.getValue(), resource);
      }
  
      @Override
      public void registerChild(final PathElement address, final int index, final Resource resource) {
          if(address.isMultiTarget()) {
              throw new IllegalArgumentException();
          }
          if (index >= 0 && !orderedChildTypes.contains(address.getKey())) {
              throw ControllerLogger.ROOT_LOGGER.indexedChildResourceRegistrationNotAvailable(address);
          }
          getOrCreateProvider(address.getKey()).register(address.getValue(), index, resource);
      }
  
      @Override
      public Resource removeChild(PathElement address) {
          synchronized (children) {
              final ResourceProvider provider = getProvider(address.getKey());
              if(provider == null) {
                  return null;
              }
              final Resource removed = provider.remove(address.getValue());
              // Cleanup default resource providers
              if ((provider instanceof DefaultResourceProvider) && !provider.hasChildren()) {
                  children.remove(address.getKey());
              }
              return removed;
          }
      }
  
      @Override
      public boolean isProxy() {
          return false;
      }
  
      @Override
      public boolean isRuntime() {
          return runtimeOnly;
      }
  
      @Override
      public Set<String> getOrderedChildTypes() {
          return orderedChildTypes;
      }
  
      protected void registerResourceProvider(final String type, final ResourceProvider provider) {
          synchronized (children) {
              if (children.containsKey(type)) {
                  throw ControllerLogger.ROOT_LOGGER.duplicateResourceType(type);
              }
              children.put(type, provider);
          }
      }
  
      protected final ResourceProvider getProvider(final String type) {
          synchronized (children) {
              return children.get(type);
          }
      }
  
      protected ResourceProvider getOrCreateProvider(final String type) {
          synchronized (children) {
              final ResourceProvider provider = children.get(type);
              if(provider != null) {
                  return provider;
              } else {
                  final ResourceProvider newProvider = new DefaultResourceProvider();
                  children.put(type, newProvider);
                  return newProvider;
              }
          }
      }
  
      @Override
      public abstract Resource clone();
  
      protected void cloneProviders(AbstractModelResource clone) {
          synchronized (children) {
              for (final Map.Entry<String, ResourceProvider> entry : children.entrySet()) {
                  clone.registerResourceProvider(entry.getKey(), entry.getValue().clone());
              }
          }
      }
  
      private static class DefaultResourceProvider implements ResourceProvider {
  
          private final Map<String, Resource> children = new LinkedHashMap<String, Resource>();
  
          protected DefaultResourceProvider() {
          }
  
          @Override
          public Set<String> children() {
              synchronized (children) {
                  return new LinkedHashSet<String>(children.keySet());
              }
          }
  
          @Override
          public boolean has(String name) {
              synchronized (children) {
                  return children.get(name) != null;
              }
          }
  
          @Override
          public Resource get(String name) {
              synchronized (children) {
                  return children.get(name);
              }
          }
  
          @Override
          public boolean hasChildren() {
              return ! children().isEmpty();
          }
  
          @Override
          public void register(String name, Resource resource) {
              synchronized (children) {
                  if (children.containsKey(name)) {
                      throw ControllerLogger.ROOT_LOGGER.duplicateResource(name);
                  }
                  children.put(name, resource);
              }
          }
  
          @Override
          public void register(String name, int index, Resource resource) {
              synchronized (children) {
                  if (children.containsKey(name)) {
                      throw ControllerLogger.ROOT_LOGGER.duplicateResource(name);
                  }
  
                  if (index < 0 || index >= children.size()) {
                      children.put(name, resource);
                  } else {
                      List<Map.Entry<String, Resource>> list = new ArrayList<Map.Entry<String,Resource>>(children.entrySet());
                      children.clear();
                      boolean done = false;
                      int i = 0;
                      for (Map.Entry<String, Resource> entry : list) {
  