gt:                 size.setAttribute ( "archive", "" + info.getArchiveSize () );
context: /*******************************************************************************
   * Copyright (c) 2015, 2016 IBH SYSTEMS GmbH 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:
   *     IBH SYSTEMS GmbH - initial API and implementation
   *     M-Ezzat - code cleanup - squid:S2131
   *     Red Hat Inc - Fix issue #81
   *******************************************************************************/
  package org.eclipse.packagedrone.utils.rpm.yum;
  
  import java.io.IOException;
  import java.io.OutputStream;
  import java.time.Instant;
  import java.util.Arrays;
  import java.util.EnumSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Objects;
  import java.util.TreeSet;
  import java.util.UUID;
  import java.util.function.Function;
  import java.util.function.Predicate;
  import java.util.regex.Pattern;
  import java.util.stream.Collectors;
  import java.util.zip.GZIPOutputStream;
  
  import javax.xml.parsers.DocumentBuilderFactory;
  import javax.xml.parsers.ParserConfigurationException;
  import javax.xml.transform.OutputKeys;
  import javax.xml.transform.Result;
  import javax.xml.transform.Transformer;
  import javax.xml.transform.TransformerException;
  import javax.xml.transform.TransformerFactory;
  import javax.xml.transform.dom.DOMSource;
  import javax.xml.transform.stream.StreamResult;
  
  import org.bouncycastle.bcpg.HashAlgorithmTags;
  import org.bouncycastle.openpgp.PGPPrivateKey;
  import org.eclipse.packagedrone.utils.io.IOConsumer;
  import org.eclipse.packagedrone.utils.io.OutputSpooler;
  import org.eclipse.packagedrone.utils.io.SpoolOutTarget;
  import org.eclipse.packagedrone.utils.rpm.HashAlgorithm;
  import org.eclipse.packagedrone.utils.rpm.RpmVersion;
  import org.eclipse.packagedrone.utils.rpm.deps.RpmDependencyFlags;
  import org.eclipse.packagedrone.utils.rpm.info.RpmInformation;
  import org.eclipse.packagedrone.utils.rpm.info.RpmInformation.Changelog;
  import org.eclipse.packagedrone.utils.rpm.info.RpmInformation.Dependency;
  import org.eclipse.packagedrone.utils.security.pgp.SigningStream;
  import org.w3c.dom.Document;
  import org.w3c.dom.Element;
  
  public class RepositoryCreator
  {
      private static final String MD_NAME = "SHA-256";
  
      private static final String MD_TAG = "sha256";
  
      private final XmlContext xml;
  
      private final OutputSpooler primaryStreamBuilder;
  
      private final OutputSpooler filelistsStreamBuilder;
  
      private final OutputSpooler otherStreamBuilder;
  
      private final OutputSpooler mdStreamBuilder;
  
      private final List<Pattern> primaryFiles;
  
      private final List<Pattern> primaryDirs;
  
      private final String primaryUniqueName;
  
      private final String filelistsUniqueName;
  
      private final String otherUniqueName;
  
      public interface XmlContext
      {
          public void write ( Document primary, OutputStream primaryStream ) throws IOException;
  
          public Document createDocument ();
      }
  
      public static class DefaultXmlContext implements XmlContext
      {
          private final DocumentBuilderFactory documentBuilderFactory;
  
          private final TransformerFactory transformerFactory;
  
          public DefaultXmlContext ()
          {
              this.documentBuilderFactory = DocumentBuilderFactory.newInstance ();
              this.documentBuilderFactory.setNamespaceAware ( true );
  
              this.transformerFactory = TransformerFactory.newInstance ();
          }
  
          public DefaultXmlContext ( final DocumentBuilderFactory documentBuilderFactory, final TransformerFactory transformerFactory )
          {
              Objects.requireNonNull ( documentBuilderFactory );
              Objects.requireNonNull ( transformerFactory );
  
              if ( !documentBuilderFactory.isNamespaceAware () )
              {
                  throw new IllegalArgumentException ( "The provided DocumentBuilderFactory must be namespace aware" );
              }
  
              this.documentBuilderFactory = documentBuilderFactory;
              this.transformerFactory = transformerFactory;
          }
  
          @Override
          public Document createDocument ()
          {
              try
              {
                  return this.documentBuilderFactory.newDocumentBuilder ().newDocument ();
              }
              catch ( final ParserConfigurationException e )
              {
                  throw new RuntimeException ( e );
              }
          }
  
          @Override
          public void write ( final Document doc, final OutputStream outputStream ) throws IOException
          {
              try
              {
                  final Transformer transformer = this.transformerFactory.newTransformer ();
                  final DOMSource source = new DOMSource ( doc );
                  final Result result = new StreamResult ( outputStream );
                  transformer.setOutputProperty ( OutputKeys.INDENT, "yes" );
                  transformer.setOutputProperty ( OutputKeys.ENCODING, "UTF-8" );
                  transformer.setOutputProperty ( "{http://xml.apache.org/xslt}indent-amount", "2" );
  
                  transformer.transform ( source, result );
              }
              catch ( final TransformerException e )
              {
                  throw new IOException ( e );
              }
          }
      }
  
      public interface Context
      {
          public void addPackage ( FileInformation fileInformation, RpmInformation rpmInformation, Map<HashAlgorithm, String> checksums, HashAlgorithm idType );
      }
  
      public static class FileInformation
      {
          private final Instant timestamp;
  
          private final long size;
  
          private final String location;
  
          public FileInformation ( final Instant timestamp, final long size, final String location )
          {
              this.timestamp = timestamp;
              this.size = size;
              this.location = location;
          }
  
          public Instant getTimestamp ()
          {
              return this.timestamp;
          }
  
          public long getSize ()
          {
              return this.size;
          }
  
          public String getLocation ()
          {
              return this.location;
          }
      }
  
      private class ContextImpl implements Context
      {
          private final OutputStream primaryStream;
  
          private final OutputStream filelistsStream;
  
          private final OutputStream otherStream;
  
          private final XmlContext xml;
  
          private final Document primary;
  
          private final Document filelists;
  
          private final Document other;
  
          private final Element primaryRoot;
  
          private final Element filelistsRoot;
  
          private final Element otherRoot;
  
          private long count;
  
          public ContextImpl ( final OutputStream primaryStream, final OutputStream filelistsStream, final OutputStream otherStream, final XmlContext xml )
          {
              this.primaryStream = primaryStream;
              this.filelistsStream = filelistsStream;
              this.otherStream = otherStream;
  
              this.xml = xml;
  
              this.primary = xml.createDocument ();
              this.primaryRoot = this.primary.createElementNS ( "http://linux.duke.edu/metadata/common", "metadata" );
              this.primaryRoot.setAttribute ( "xmlns:rpm", "http://linux.duke.edu/metadata/rpm" );
              this.primary.appendChild ( this.primaryRoot );
  
              this.filelists = xml.createDocument ();
              this.filelistsRoot = this.filelists.createElementNS ( "http://linux.duke.edu/metadata/filelists", "filelists" );
              this.filelists.appendChild ( this.filelistsRoot );
  
              this.other = xml.createDocument ();
              this.otherRoot = this.other.createElementNS ( "http://linux.duke.edu/metadata/other", "otherdata" );
              this.other.appendChild ( this.otherRoot );
          }
  
          @Override
          public void addPackage ( final FileInformation fileInformation, final RpmInformation info, final Map<HashAlgorithm, String> checksums, final HashAlgorithm idType )
          {
              Objects.requireNonNull ( fileInformation );
              Objects.requireNonNull ( info );
              Objects.requireNonNull ( checksums );
              Objects.requireNonNull ( idType );
  
              final String id = checksums.get ( idType );
              if ( id == null || id.isEmpty () )
              {
                  throw new IllegalArgumentException ( String.format ( "Checksums map did not contain a value for the ID type: %s", idType ) );
              }
  
              this.count++;
  
              // insert to primary
  
              insertToPrimary ( fileInformation, info, checksums, idType );
  
              // insert to "filelists"
  
              {
                  final Element pkg = createPackage ( this.filelistsRoot, id, info );
                  appendFiles ( info, pkg, null, null );
              }
  
              // insert to "other"
  
              {
                  final Element pkg = createPackage ( this.otherRoot, id, info );
                  for ( final Changelog log : info.getChangelog () )
                  {
                      final Element cl = addElement ( pkg, "changelog", log.getText () );
                      cl.setAttribute ( "author", log.getAuthor () );
                      cl.setAttribute ( "date", "" + log.getTimestamp () );
                  }
              }
          }
  
          private void appendFiles ( final RpmInformation info, final Element pkg, final Predicate<String> fileFilter, final Predicate<String> dirFilter )
          {
              for ( final String file : new TreeSet<> ( info.getFiles () ) )
              {
                  if ( fileFilter == null || fileFilter.test ( file ) )
                  {
                      addElement ( pkg, "file", file );
                  }
              }
              for ( final String dir : new TreeSet<> ( info.getDirectories () ) )
              {
                  if ( dirFilter == null || dirFilter.test ( dir ) )
                  {
                      final Element ele = addElement ( pkg, "file", dir );
                      ele.setAttribute ( "type", "dir" );
                  }
              }
          }
  
          private void insertToPrimary ( final FileInformation fileInformation, final RpmInformation info, final Map<HashAlgorithm, String> checksums, final HashAlgorithm idType )
          {
              final Element pkg = addElement ( this.primaryRoot, "package" );
              pkg.setAttribute ( "type", "rpm" );
  
              addElement ( pkg, "name", info.getName () );
              addElement ( pkg, "arch", info.getArchitecture () );
  
              addVersion ( pkg, info.getVersion () );
  
              for ( final Map.Entry<HashAlgorithm, String> entry : checksums.entrySet () )
              {
                  final Element checksum = addElement ( pkg, "checksum", entry.getValue () );
                  checksum.setAttribute ( "type", entry.getKey ().getId () );
                  if ( entry.getKey () == idType )
                  {
                      checksum.setAttribute ( "pkgid", "YES" );
                  }
              }
  
              addElement ( pkg, "summary", info.getSummary () );
              addElement ( pkg, "description", info.getDescription () );
              addElement ( pkg, "packager", info.getPackager () );
              addElement ( pkg, "url", info.getUrl () );
  
              // time
  
              final Element time = addElement ( pkg, "time" );
              time.setAttribute ( "file", "" + fileInformation.getTimestamp ().getEpochSecond () );
              if ( info.getBuildTimestamp () != null )
              {
                  time.setAttribute ( "build", "" + info.getBuildTimestamp () );
              }
  
              // size
  
              final Element size = addElement ( pkg, "size" );
              size.setAttribute ( "package", "" + fileInformation.getSize () );
              if ( info.getInstalledSize () != null )
              {
                  size.setAttribute ( "installed", "" + info.getInstalledSize () );
              }
              if ( info.getArchiveSize () != null )
              {
  