/* * Copyright 2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.kuujo.vertigo.io; import java.io.File; import net.kuujo.vertigo.io.group.OutputGroup; import org.vertx.java.core.AsyncResult; import org.vertx.java.core.Handler; import org.vertx.java.core.buffer.Buffer; import org.vertx.java.core.file.AsyncFile; import org.vertx.java.core.impl.DefaultFutureResult; /** * Output file sender.<p> * * The file sender uses an output group to send a file to target component(s). * Since Vertigo guarantees message ordering, the file can be sent asynchronously * rather than waiting for replies from the target components. Once the entire * file has been sent the group will be closed.<p> * * You should use a {@link FileReceiver} to receive files on an input port. * * @author <a href="http://github.com/kuujo">Jordan Halterman</a> */ public class FileSender { private static final int BUFFER_SIZE = 4096; private final Output<?> output; public FileSender(Output<?> output) { this.output = output; } /** * Sends a file on the output port. * * @param file The file to send. * @return The file sender. */ public FileSender sendFile(AsyncFile file) { return sendFile(file, null); } /** * Sends a file on the output port. * * @param file The file to send. * @param doneHandler An asynchronous handler to be called once the file has been sent. * @return The file sender. */ public FileSender sendFile(final AsyncFile file, final Handler<AsyncResult<Void>> doneHandler) { output.group("file", "file", new Handler<OutputGroup>() { @Override public void handle(OutputGroup group) { doSendFile(file, group, doneHandler); } }); return this; } /** * Sends a file on the output port. * * @param filePath The path to the file to send. * @return The file sender. */ public FileSender sendFile(String filePath) { return sendFile(filePath, null); } /** * Sends a file on the output port. * * @param filePath The path to the file to send. * @param doneHandler An asynchronous handler to be called once the file has been sent. * @return The file sender. */ public FileSender sendFile(String filePath, final Handler<AsyncResult<Void>> doneHandler) { final File file = new File(filePath); output.vertx().fileSystem().exists(file.getAbsolutePath(), new Handler<AsyncResult<Boolean>>() { @Override public void handle(AsyncResult<Boolean> result) { if (result.failed()) { new DefaultFutureResult<Void>(result.cause()).setHandler(doneHandler); } else if (!result.result()) { new DefaultFutureResult<Void>(new IOException("File not found.")).setHandler(doneHandler); } else { output.group("file", file.getName(), new Handler<OutputGroup>() { @Override public void handle(final OutputGroup group) { output.vertx().fileSystem().open(file.getAbsolutePath(), new Handler<AsyncResult<AsyncFile>>() { @Override public void handle(AsyncResult<AsyncFile> result) { if (result.failed()) { new DefaultFutureResult<Void>(result.cause()).setHandler(doneHandler); } else { doSendFile(result.result(), group, doneHandler); } } }); } }); } } }); return this; } /** * Sends the file to the given output group. */ private void doSendFile(final AsyncFile file, final OutputGroup group, final Handler<AsyncResult<Void>> doneHandler) { doSendFile(file, group, 0, doneHandler); } /** * Sends the file to the given output group. */ private void doSendFile(final AsyncFile file, final OutputGroup group, final int position, final Handler<AsyncResult<Void>> doneHandler) { if (!group.sendQueueFull()) { file.read(new Buffer(BUFFER_SIZE), 0, position, BUFFER_SIZE, new Handler<AsyncResult<Buffer>>() { @Override public void handle(AsyncResult<Buffer> result) { if (result.failed()) { new DefaultFutureResult<Void>(result.cause()).setHandler(doneHandler); } else { Buffer buffer = result.result(); if (buffer.length() > 0) { group.send(buffer); doSendFile(file, group, position+buffer.length(), doneHandler); } else { group.end(); new DefaultFutureResult<Void>((Void) null).setHandler(doneHandler); } } } }); } else { group.drainHandler(new Handler<Void>() { @Override public void handle(Void event) { doSendFile(file, group, position, doneHandler); } }); } } }