/* Copyright (c) 2014 Boundless and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Distribution License v1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/edl-v10.html * * Contributors: * Gabriel Roldan (Boundless) - initial implementation */ package org.locationtech.geogig.remote; import java.io.IOException; import java.io.OutputStream; import org.locationtech.geogig.api.RevObject; import org.locationtech.geogig.storage.ObjectSerializingFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Supplier; import com.google.common.io.CountingOutputStream; public class ObjectFunnels { private static final Logger LOGGER = LoggerFactory.getLogger(ObjectFunnels.class); public static ObjectFunnel newFunnel(OutputStream out, ObjectSerializingFactory serializer) { return new DirectFunnel(out, serializer); } public static ObjectFunnel newFunnel(final Supplier<OutputStream> outputFactory, final ObjectSerializingFactory serializer, final int byteSoftLimit) { return new SizeLimitingFunnel(outputFactory, serializer, byteSoftLimit); } private static class DirectFunnel implements ObjectFunnel { private OutputStream out; private ObjectSerializingFactory serializer; public DirectFunnel(OutputStream out, ObjectSerializingFactory serializer) { this.out = out; this.serializer = serializer; } @Override public void funnel(RevObject object) throws IOException { out.write(object.getId().getRawValue()); serializer.createObjectWriter(object.getType()).write(object, out); } @Override public void close() throws IOException { OutputStream out = this.out; this.out = null; if (out != null) { out.close(); } } } private static class SizeLimitingFunnel implements ObjectFunnel { private Supplier<OutputStream> outputFactory; private final ObjectSerializingFactory serializer; private final int byteSoftLimit; private CountingOutputStream currentTarget; public SizeLimitingFunnel(Supplier<OutputStream> outputFactory, ObjectSerializingFactory serializer, final int byteSoftLimit) { this.outputFactory = outputFactory; this.serializer = serializer; this.byteSoftLimit = byteSoftLimit; } @Override public void funnel(RevObject object) throws IOException { OutputStream out = getCurrentTarget(); out.write(object.getId().getRawValue()); serializer.createObjectWriter(object.getType()).write(object, out); out.flush(); } private OutputStream getCurrentTarget() throws IOException { if (currentTarget == null) { currentTarget = new CountingOutputStream(outputFactory.get()); } else if (currentTarget.getCount() >= byteSoftLimit) { LOGGER.info(String.format( "Closing stream and opening a new one, reached %,d bytes.\n", currentTarget.getCount())); currentTarget.close(); currentTarget = new CountingOutputStream(outputFactory.get()); } return currentTarget; } @Override public void close() throws IOException { OutputStream currentTarget = this.currentTarget; this.currentTarget = null; if (currentTarget != null) { currentTarget.close(); } outputFactory = null; } } }