private final void mergeNetworkTables() throws UnsupportedEncodingException {
    for (final Entry<Long, Set<CyTableMetadataBuilder>> entry : networkTableMap.entrySet()) {
      final Object oldId = entry.getKey();
      final Set<CyTableMetadataBuilder> builders = entry.getValue();
      final CyNetwork network = cache.getNetwork(oldId);

      if (network == null) {
        logger.error("Cannot merge network tables: Cannot find network " + oldId);
        continue;
      }

      for (final CyTableMetadataBuilder builder : builders) {
        if (cancelled) return;

        builder.setNetwork(network);
        mergeNetworkTable(network, builder);
        CyTableMetadata metadata = builder.build();
        tableMetadata.add(metadata);

        // Update filename<->table maps
        final String filename = builderFilenameMap.get(builder);
        filenameTableMap.put(filename, metadata.getTable());
      }
    }
  }
  private void extractTable(InputStream stream, String entryName) throws Exception {
    CyTableReader reader =
        (CyTableReader) csvCyReaderFactory.createTaskIterator(stream, entryName).next();
    reader.run(taskMonitor);

    // Assume one table per entry
    CyTable table = reader.getTables()[0];
    Matcher matcher = NETWORK_TABLE_PATTERN.matcher(entryName);

    if (matcher.matches()) {
      String networkName = SessionUtil.unescape(matcher.group(2));
      Long oldNetId = getOldNetworkId(networkName);

      if (oldNetId == null) {
        throw new NullPointerException(
            "Cannot extract table. Network SUID is null for entry: " + entryName);
      }

      String namespace = SessionUtil.unescape(matcher.group(3));
      Class<?> type = Class.forName(SessionUtil.unescape(matcher.group(4)));
      String title = SessionUtil.unescape(matcher.group(5));
      table.setTitle(title);
      CyTableMetadataBuilder builder =
          new CyTableMetadataBuilder().setCyTable(table).setNamespace(namespace).setType(type);
      Set<CyTableMetadataBuilder> builders = networkTableMap.get(oldNetId);

      if (builders == null) {
        builders = new HashSet<CyTableMetadataBuilder>();
        networkTableMap.put(oldNetId, builders);
      }

      builders.add(builder);

      String filename = matcher.group(1);
      filenameTableMap.put(filename, table);
      builderFilenameMap.put(builder, filename);

      return;
    }

    matcher = GLOBAL_TABLE_PATTERN.matcher(entryName);

    if (matcher.matches()) {
      String title = SessionUtil.unescape(matcher.group(3));
      table.setTitle(title);
      CyTableMetadataBuilder builder =
          new CyTableMetadataBuilder().setCyTable(table).setNetwork(null);
      tableMetadata.add(builder.build());

      String filename = matcher.group(1);
      filenameTableMap.put(filename, table);
      builderFilenameMap.put(builder, filename);

      // Look for SUID-type columns--only global tables now
      suidUpdater.addTable(table);
    }
  }
  @SuppressWarnings("unchecked")
  private final void mergeNetworkTable(CyNetwork network, CyTableMetadataBuilder builder) {
    final Class<? extends CyIdentifiable> type =
        (Class<? extends CyIdentifiable>) builder.getType();
    final String namespace = builder.getNamespace();
    final CyTable src = builder.getTable();
    final CyTable tgt = networkTableMgr.getTable(network, type, namespace);

    if (tgt == null) {
      // Just use the source table
      networkTableMgr.setTable(network, type, namespace, src);
      builder.setCyTable(src);

      suidUpdater.addTable(src);
    } else {
      mergeTables(src, tgt, type);
      builder.setCyTable(tgt);

      suidUpdater.addTable(tgt);
    }
  }