gt:         if (type == COLLECTION) {
context: /*******************************************************************************
   * Copyright (c) 2019 IBM Corporation and others.
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *     IBM Corporation - initial API and implementation
   *******************************************************************************/
  package com.ibm.ws.config.admin.internal;
  
  import java.io.BufferedInputStream;
  import java.io.BufferedOutputStream;
  import java.io.DataInputStream;
  import java.io.DataOutputStream;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.lang.reflect.Array;
  import java.util.AbstractMap.SimpleEntry;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Dictionary;
  import java.util.Enumeration;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import com.ibm.ws.config.admin.ConfigID;
  import com.ibm.ws.config.admin.ConfigurationDictionary;
  import com.ibm.ws.config.admin.ExtendedConfiguration;
  import com.ibm.ws.ffdc.annotation.FFDCIgnore;
  import com.ibm.wsspi.kernel.service.utils.OnErrorUtil.OnError;
  import com.ibm.wsspi.kernel.service.utils.SerializableProtectedString;
  
  /**
   * A helper class for storing and retrieving the persisted config information.
   * <p>
   * {@link #load(File, ConfigStorageConsumer)} / {@link #store(File, Collection)} format: <br>
   * byte - version, set to constant {@link #VERSION} <br>
   * int - number of configurations <br>
   * followed by the list of conditions as loaded by {@link #load(DataInputStream, Set, Set, ConfigurationDictionary)}
   * <p>
   * {@link #load(DataInputStream, Set, Set, ConfigurationDictionary)} / {@link #store(DataOutputStream, Dictionary, String, Set, Set)} format: <br>
   * utf - bundleLocation <br>
   * int - number of unique variables <br>
   * utf - unique variables, write the number of entries dictated by prior <br>
   * int - number of config references <br>
   * configIDs - the config ids written parent to child in order. <br>
   * int - optionaly. Written if this a parent to indicate how many entries in this tree <br>
   * utf - the id <br>
   * utf - the pid <br>
   * utf - the child attribute <br>
   * int - an index to which config id is the parent. If an entry is -1 it means it has no parent. <br>
   * int - the number of entries in the config dictionary <br>
   * entries - the entries in the config dictionary <br>
   * utf - the name of the entry <br>
   * int - the type of the entry <br>
   * <value> - the value. How this is written depends on whether it is primitive, collection, array or map. <br>
   * - primitives are written directly <br>
   * - collections have their size written followed by each entry <br>
   * - arrays have their size written followed by each entry <br>
   * - maps are written the same way as the main config dictionary <br>
   */
  public class ConfigurationStorageHelper {
  
      public static interface ConfigStorageConsumer<K, T> {
          T consumeConfigData(String location, Set<String> uniqueVars, Set<ConfigID> references, ConfigurationDictionary dict);
  
          K getKey(T consumerType);
      }
  
      private static final byte VERSION = 0;
      private static final byte BYTE = 0;
      private static final byte SHORT = 1;
      private static final byte BOOLEAN = 2;
      private static final byte CHAR = 3;
      private static final byte DOUBLE = 4;
      private static final byte LONG = 5;
      private static final byte FLOAT = 6;
      private static final byte INTEGER = 7;
      private static final byte STRING = 8;
      private static final byte PROTECTED_STRING = 9;
      private static final byte COLLECTION = 10;
      private static final byte MAP = 11;
      private static final byte ARRAY = 12;
      private static final byte ONERROR = 13;
      private static final byte NULL = 14;
      private static final byte OBJECT = 15;
  
      public static <K, T> Map<K, T> load(File configFile, ConfigStorageConsumer<K, T> consumer) throws IOException {
          Map<K, T> result = new HashMap<>();
          try (DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(configFile)))) {
              if (dis.readByte() == VERSION) {
                  int numConfigs = dis.readInt();
                  for (int i = 0; i < numConfigs; i++) {
                      Set<String> uniqueVars = new HashSet<>();
                      Set<ConfigID> references = new HashSet<>();
                      ConfigurationDictionary dict = new ConfigurationDictionary();
                      String location = load(dis, uniqueVars, references, dict);
                      T value = consumer.consumeConfigData(location, uniqueVars, references, dict);
                      result.put(consumer.getKey(value), value);
                  }
              }
          }
          return result;
      }
  
      static String load(DataInputStream dis, Set<String> uniqueVars, Set<ConfigID> references, ConfigurationDictionary dict) throws IOException {
          String location = (String) readObject(dis);
          int len = dis.readInt();
          for (int i = 0; i < len; i++) {
              uniqueVars.add(dis.readUTF());
          }
          len = dis.readInt();
          List<ConfigID> ids = new ArrayList<>();
          for (int i = 0, j = 0, cursor = 0; i < len + cursor; i++, j++) {
              if (cursor == 0) {
                  cursor = dis.readInt();
                  j = 0;
              }
              String id = (String) readObject(dis);
              String configPid = dis.readUTF();
              String child = (String) readObject(dis);
              int parentId = dis.readInt();
              ConfigID parent = null;
              if (parentId > -1) {
                  parent = ids.get(parentId);
              }
              ConfigID thisId = new ConfigID(parent, configPid, id, child);
              ids.add(thisId);
  
              if (j == cursor) {
                  len = len + cursor;
                  cursor = 0;
                  references.add(thisId);
              }
          }
          readMapInternal(dis, toMapOrDictionary(dict));
          return location;
  
      }
  
      @FFDCIgnore(IllegalStateException.class)
      public static void store(File configFile, Collection<? extends ExtendedConfiguration> configs) throws IOException {
          try (DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(configFile, false)))) {
              dos.writeByte(VERSION);
              // This secondary list is needed so we can collect the valid number of configs:
              // non-null properties and not deleted (indicated with an IllegalStateException)
              List<Object[]> configDatas = new ArrayList<>(configs.size());
              for (ExtendedConfiguration config : configs) {
                  try {
                      Dictionary<String, ?> properties = config.getReadOnlyProperties();
                      Set<ConfigID> references = config.getReferences();
                      Set<String> uniqueVars = config.getUniqueVariables();
                      String bundleLocation = config.getBundleLocation();
                      if (properties != null) {
                          configDatas.add(new Object[] { properties, references, uniqueVars, bundleLocation });
                      }
                  } catch (IllegalStateException e) {
                      // ignore FFDC
                  }
              }
              // now we have all the valid configs and their dictionaries to save
              dos.writeInt(configDatas.size());
              for (Object[] configData : configDatas) {
                  @SuppressWarnings("unchecked")
                  Dictionary<String, ?> properties = (Dictionary<String, ?>) configData[0];
                  @SuppressWarnings("unchecked")
                  Set<ConfigID> references = (Set<ConfigID>) configData[1];
                  @SuppressWarnings("unchecked")
                  Set<String> uniqueVars = (Set<String>) configData[2];
                  String bundleLocation = (String) configData[3];
                  store(dos, properties, bundleLocation, references, uniqueVars);
              }
          }
      }
  
      static void store(DataOutputStream dos, Dictionary<String, ?> properties, String bundleLocation,
                        Set<ConfigID> references, Set<String> uniqueVars) throws IOException {
  
          writeObject(dos, bundleLocation);
          if (uniqueVars != null) {
              dos.writeInt(uniqueVars.size());
              for (String var : uniqueVars) {
                  dos.writeUTF(var);
              }
          } else {
              dos.writeInt(0);
          }
          if (references != null) {
              dos.writeInt(references.size());
              int count = 0;
              Map<ConfigID, Integer> writtenConfigIds = new HashMap<>();
              for (ConfigID id : references) {
                  count = writeConfigID(dos, id, count, 0, writtenConfigIds);
              }
          } else {
              dos.writeInt(0);
          }
          writeMapInternal(dos, toMapOrDictionary(properties));
      }
  
      public static void readMap(DataInputStream dis, MapIterable props) throws IOException {
          if (dis.readByte() != VERSION) {
              return;
          }
          readMapInternal(dis, props);
      }
  
      private static void readMapInternal(DataInputStream dis, MapIterable props) throws IOException {
          int size = dis.readInt();
          for (int i = 0; i < size; i++) {
              String key = dis.readUTF();
              Object value = readMapValue(dis);
              props.put(key, value);
          }
      }
  
      private static Object readMapValue(DataInputStream dis) throws IOException {
          byte type = dis.readByte();
          Object value;
  
  