@Override
    public void receive(final Instant startTime,
                        final AttributeMap attributeMap,
                        final String requestUri,
                        final InputStreamSupplier inputStreamSupplier) {

        final Path receivingDir;
        final ReceiveResult receiveResult;
        try {
            receivingDir = receivingDirProvider.get();
            final FileGroup fileGroup = new FileGroup(receivingDir);
            final Path sourceZip = fileGroup.getZip();
            try {
                receiveResult = receiveZipStream(
                        inputStreamSupplier.get(),
                        attributeMap,
                        sourceZip);
            } catch (final Exception e) {
                LOGGER.debug(() -> LogUtil.exceptionMessage(e), e);
                // Cleanup.
                Files.deleteIfExists(sourceZip);
                deleteDir(receivingDir);
                throw StroomStreamException.create(e, attributeMap);
            }

            if (LOGGER.isDebugEnabled() && receiveResult.feedGroups.size() > 1) {
                // Log if we received a multi feed zip.
                logFeedGroupsToDebug(receiveResult);
            }

            // Check all the feeds are OK.
            final Map<FeedKey, List<ZipEntryGroup>> allowedEntries = filterAllowedEntries(
                    attributeMap, receiveResult);

            // Only keep data for allowed feeds.
            if (!allowedEntries.isEmpty()) {
                // Write out the allowed entries so the destination knows which entries are in the zip
                // that are allowed to be used, i.e. so zipSplitter can drop zip entries that have no
                // corresponding entry in the entries file
                writeZipEntryGroups(fileGroup.getEntries(), allowedEntries);

                // If the data we received was for a perfectly formed zip file with data for a single feed then don't
                // bother to rewrite it in the zipSplitter.
                final int feedGroupCount = receiveResult.feedGroups.size();
                if (receiveResult.valid && feedGroupCount == 1) {
                    final FeedKey feedKey = allowedEntries.keySet().iterator().next();

                    // Write meta. Single feed/type so add them to the attr map
                    AttributeMapUtil.addFeedAndType(attributeMap, feedKey.feed(), feedKey.type());
                    AttributeMapUtil.write(attributeMap, fileGroup.getMeta());

                    // Move receiving dir to destination.
                    LOGGER.debug("Pass {} with feedKey: {} to destination {}", receivingDir, feedKey, destination);
                    destination.accept(receivingDir);
                } else {
                    // We have more than one feed in the source zip so split the source into a zip file for each feed.
                    // Before we can queue the zip for splitting we need to serialise the attr map, so it is
                    // available for the split process.
                    AttributeMapUtil.write(attributeMap, fileGroup.getMeta());
                    LOGGER.debug(() -> LogUtil.message("Pass {} to zipSplitter, isValid: {}, feedGroupCount: {}",
                            receivingDir, receiveResult.valid, feedGroupCount));
                    zipSplitter.add(receivingDir);
                }
            } else {
                LOGGER.debug("No allowed feedKeys, all are dropped");
                // Delete the source zip.
                Files.delete(sourceZip);
                deleteDir(receivingDir);
            }
        } catch (final IOException e) {
            throw StroomStreamException.create(e, attributeMap);
        }

        final Duration duration = Duration.between(startTime, Instant.now());
        logStream.log(
                RECEIVE_LOG,
                attributeMap,
                EventType.RECEIVE,
                requestUri,
                StroomStatusCode.OK,
                attributeMap.get(StandardHeaderArguments.RECEIPT_ID),
                receiveResult.receivedBytes,
                duration.toMillis());
    }
<p>
This class deals with the reception of zip files. It will perform the following tasks:
1. Streams the zip file to disk, recording zip entries and reading meta data as it goes.
2. It tries to match all data entries to associated meta data.
3. It finds all unique feeds and checks the status for each feed. An entries file is created containing
a line for all allowed entries in the zip, which will be used by {@link ZipSplitter} to split the zips.
4. If the zip contains multiple feedKeys or is not in proper proxy zip format it passes
it to the ZipSplitter, else if passed it to the destination.
</p><p>
Along with the final zip files there will be associated meta files written to use for forwarding.
There will also be an entries file that tells us the size of each file set. The entries file has a JSON string
for each set of files in the zip. This data allows us to understand how best to aggregate this data if required.
</p>
stroom-proxy/stroom-proxy-app/src/main/java/stroom/proxy/app/handler/ZipReceiver.java