/**
  * Remove the given object from this AbstractReferenceManufacturer. Returns true if the object was
  * removed from this AbstractReferenceManufacturer; false otherwise.
  *
  * @param item The object to be removed from this AbstractReferenceManufacturer.
  * @return true if the object was removed from this AbstractReferenceManufacturer; false
  *     otherwise.
  */
 @Override
 public boolean forgetObject(T item) {
   if (!factory.isMember(item)) {
     throw new IllegalArgumentException(
         "Object to be forgotten does not match Class " + "of this AbstractReferenceManufacturer");
   }
   String key = active.getKeyFor(item);
   if (key == null) {
     /*
      * TODO This is a bug - the key name is not necessarily loaded into
      * the object, it may have been consumed by the object context... :P
      */
     CaseInsensitiveString ocik = new CaseInsensitiveString(item.getKeyName());
     duplicates.removeFromListFor(ocik, item);
   } else {
     CaseInsensitiveString ocik = new CaseInsensitiveString(key);
     List<T> list = duplicates.getListFor(ocik);
     if (list == null) {
       // No replacement
       active.remove(key);
     } else {
       T newActive = duplicates.getElementInList(ocik, 0);
       duplicates.removeFromListFor(ocik, newActive);
       active.put(key, newActive);
     }
   }
   return true;
 }
 private boolean validateDuplicates() {
   boolean returnGood = true;
   for (CaseInsensitiveString second : duplicates.getKeySet()) {
     List<T> list = duplicates.getListFor(second);
     T good = active.get(second.toString());
     /*
      * CONSIDER Should get CDOMObject reference out of here :(
      */
     if (good instanceof CDOMObject) {
       CDOMObject cdo = (CDOMObject) good;
       for (int i = 0; i < list.size(); i++) {
         T dupe = list.get(i);
         if (cdo.isCDOMEqual((CDOMObject) dupe)) {
           for (Iterator<WeakReference<T>> it = manufactured.iterator(); it.hasNext(); ) {
             WeakReference<T> wr = it.next();
             T mfg = wr.get();
             if (mfg == null) {
               it.remove();
             }
             // Yes this is instance equality, not .equals
             else if (mfg == good) {
               forgetObject(good);
               break;
             }
           }
         }
       }
     }
     if (duplicates.containsListFor(second)) {
       Logging.errorPrint(
           "More than one "
               + factory.getReferenceDescription()
               + " with key/name "
               + good.getKeyName()
               + " was built");
       List<T> dupes = duplicates.getListFor(second);
       StringBuilder sb = new StringBuilder(1000);
       sb.append("Sources: ");
       sb.append(good.isInternal() ? "<internal>" : good.getSourceURI());
       for (T dupe : dupes) {
         sb.append(", ").append(dupe.isInternal() ? "<internal>" : dupe.getSourceURI());
         if (!dupe.getKeyName().equals(good.getKeyName())) {
           Logging.errorPrint("Key case differed for " + dupe.getKeyName());
         }
       }
       Logging.errorPrint(sb.toString());
       returnGood = false;
     }
   }
   return returnGood;
 }
 /**
  * Injects all objects from the given ReferenceManufacturer into this
  * AbstractReferenceManufacturer. Effectively this is a bulk addObject for all of the objects
  * contained in the given ReferenceManufacturer.
  *
  * <p>Note that this imports only the objects, and NOT references. This
  * AbstractReferenceManufacturer does inherit any deferred objects (triggered through
  * constructIfNecessary) from the given ReferenceManufacturer.
  *
  * @param arm The ReferenceManufacturer from which the objects should be imported into this
  *     AbstractReferenceManufacturer
  */
 @Override
 public void injectConstructed(ReferenceManufacturer<T> arm) {
   // Must maintain order
   for (T value : active.insertOrderValues()) {
     arm.addObject(value, active.getKeyFor(value));
   }
   for (CaseInsensitiveString cis : duplicates.getKeySet()) {
     for (T obj : duplicates.getListFor(cis)) {
       arm.addObject(obj, cis.toString());
     }
   }
   for (String s : deferred) {
     arm.constructIfNecessary(s);
   }
 }
 /**
  * Gets the object represented by the given identifier. Will return null if an object with the
  * given identifier is not present in this AbstractReferenceManufacturer.
  *
  * <p>Note that this is testing *object* presence. This will not return an object if a reference
  * for the given identifier has been requested; it will only return true if an object with the
  * given identifier has actually been constructed by or imported into this
  * AbstractReferenceManufacturer.
  *
  * @param key identifier of the object to be returned
  * @return The object stored in this AbstractReferenceManufacturer with the given identifier, or
  *     null if this AbstractReferenceManufacturer does not contain an object with the given
  *     identifier.
  */
 @Override
 public T getObject(String key) {
   T po = active.get(key);
   if (po != null) {
     List<T> list = duplicates.getListFor(new CaseInsensitiveString(key));
     if ((list != null) && !list.isEmpty()) {
       Logging.errorPrint(
           "Reference to Constructed "
               + factory.getReferenceDescription()
               + " "
               + key
               + " is ambiguous");
       StringBuilder sb = new StringBuilder(1000);
       sb.append("Locations: ");
       sb.append(po.getSourceURI());
       for (T dupe : list) {
         sb.append(", ");
         sb.append(dupe.getSourceURI());
       }
       Logging.errorPrint(sb.toString());
     }
     return po;
   }
   return null;
 }
 /**
  * Adds an object to the contents of this AbstractReferenceManufacturer. This is used in
  * conditions where this AbstractReferenceManufacturer was not used to construct the object.
  *
  * <p>Implementation Note: There are various situations where this "external construction" may
  * happen - the primary one being loading of "game mode" information like CDOMStat objects.
  *
  * @param item The object to be imported into this AbstractReferenceManufacturer
  * @param key The identifier of the object to be imported into this AbstractReferenceManufacturer
  * @throws IllegalArgumentException if the given object is not of the Class that this
  *     AbstractReferenceManufacturer constructs and references
  */
 @Override
 public void addObject(T item, String key) {
   if (!factory.isMember(item)) {
     throw new IllegalArgumentException(
         "Attempted to register a "
             + item.getClass().getName()
             + " in "
             + factory.getReferenceDescription());
   }
   T current = active.get(key);
   if (current == null) {
     active.put(key, item);
   } else {
     duplicates.addToListFor(new CaseInsensitiveString(key), item);
   }
 }