@Override public void onResponse(IResponse response) { if (!(response instanceof FilePushResponse)) { logger.error( "Expected response to be instance of " + FilePushResponse.class.getName() + " but got " + response.getClass().getName()); return; } if (StatusCode.ERROR.equals(((FilePushResponse) response).getStatusCode()) || 0 > ((FilePushResponse) response).getChunkCounter()) { // exchange is finished or an error occurred on the other side super.node .getObjectDataReplyHandler() .removeResponseCallbackHandler(response.getExchangeId()); super.onResponse(response); this.chunkCountDownLatch.countDown(); } else { this.sendChunk( ((FilePushResponse) response).getChunkCounter(), this.fileId, this.owner, response.getExchangeId(), new NodeLocation( response.getClientDevice().getUserName(), response.getClientDevice().getClientDeviceId(), response.getClientDevice().getPeerAddress())); } }
@Override public void await(long timeout, TimeUnit timeUnit) throws InterruptedException { // only wait for parent if we actually have sent a request if (this.clientCounter > 0) { super.await(timeout, timeUnit); } // wait for receivers to be initialised this.initReceiverLatch.await(timeout, timeUnit); this.chunkCountDownLatch.await(timeout, timeUnit); }
@Override public void await() throws InterruptedException { // only wait for parent if we actually have sent a request if (this.clientCounter > 0) { super.await(); } // wait for receivers to be initialised this.initReceiverLatch.await(); this.chunkCountDownLatch.await(MAX_FILE_WAITNG_TIME, TimeUnit.MILLISECONDS); }
/** * Send a chunk to another client * * @param chunkCounter The chunk counter * @param exchangeId The exchange id for the request * @param receiver The receiver which should get the chunk */ protected void sendChunk( long chunkCounter, UUID fileId, String owner, UUID exchangeId, NodeLocation receiver) { Chunk chunk = new Chunk("", "", new HashSet<>(), true, AccessType.WRITE, -1, -1, -1, null); try { chunk = this.chunkProvider.getChunk(chunkCounter, CHUNK_SIZE); } catch (InputOutputException e) { logger.error( "Failed to read the chunk " + chunkCounter + " of file " + this.relativeFilePath + " for exchange " + this.exchangeId + ". Aborting file push exchange. Message: " + e.getMessage()); return; } catch (IllegalArgumentException e) { // requested chunk does not exist anymore logger.info( "Detected file change during push exchange " + this.exchangeId + ". Starting to push again at chunk 0"); try { chunk = this.chunkProvider.getChunk(0, CHUNK_SIZE); } catch (InputOutputException e1) { logger.error( "Failed to read the chunk " + chunkCounter + " of file " + this.relativeFilePath + " for exchange " + this.exchangeId + " after detected file change. Aborting file push exchange. Message: " + e.getMessage()); } } // check whether the chunk counter has changed StatusCode statusCode = (chunkCounter == chunk.getChunkCounter()) ? StatusCode.NONE : StatusCode.FILE_CHANGED; IRequest request = new FilePushRequest( exchangeId, statusCode, this.clientDevice, chunk.getChecksum(), fileId, owner, chunk.getAccessType(), chunk.getSharers(), this.relativeFilePath, chunk.isFile(), chunk.getChunkCounter(), CHUNK_SIZE, chunk.getTotalNrOfChunks(), chunk.getTotalFileSize(), chunk.getData(), receiver); logger.info( "Sending chunk " + chunkCounter + " to client " + receiver.getPeerAddress().inetAddress().getHostAddress() + ":" + receiver.getPeerAddress().tcpPort()); super.sendRequest(request); }
@Override public void run() { try { // check whether the own client is also in the list (should be usually, but you never know...) this.clientCounter = this.receivers.size(); for (NodeLocation location : this.receivers) { if (location.getPeerAddress().equals(this.node.getPeerAddress())) { this.clientCounter--; break; } } this.chunkCountDownLatch = new CountDownLatch(this.clientCounter); this.initReceiverLatch.countDown(); // check whether we got access to the file this.fileId = null; this.owner = null; try { PathObject pathObject = this.objectStore.getObjectManager().getObjectForPath(this.relativeFilePath); // if we are not the owner but have access to the file if (null != pathObject.getOwner() && !this.node.getUser().getUserName().equals(pathObject.getOwner()) && AccessType.WRITE.equals(pathObject.getAccessType())) { try { this.fileId = this.node.getIdentifierManager().getValue(this.relativeFilePath); this.owner = pathObject.getOwner(); } catch (InputOutputException e) { logger.error( "Failed to get file id for " + this.relativeFilePath + ". Message: " + e.getMessage()); } } // add file id also if the path is shared if (pathObject.isShared()) { for (Sharer entry : pathObject.getSharers()) { try { // ask sharer's clients to get the changes too List<NodeLocation> sharerLocations = this.nodeManager.getNodeLocations(entry.getUsername()); // only add one client of the sharer. He may propagate the change then // to his clients, and if a conflict occurs, there will be a new file if (!sharerLocations.isEmpty()) { fileId = super.node.getIdentifierManager().getValue(pathObject.getAbsolutePath()); // Note that we do not add the sharer location again since these // are assembled in FileOfferExchangeHandlerResult } } catch (InputOutputException e) { logger.error( "Could not get client locations of sharer " + entry.getUsername() + ". This sharer's clients do not get the file (change)"); } } } } catch (InputOutputException e) { logger.error( "Failed to read path object for " + this.relativeFilePath + ". Message: " + e.getMessage()); } // the owner of a file is only added on a share request for (NodeLocation location : this.receivers) { UUID uuid = UUID.randomUUID(); logger.info( "Sending first chunk as subRequest of " + this.exchangeId + " with id " + uuid + " to client " + location.getPeerAddress().inetAddress().getHostName() + ":" + location.getPeerAddress().tcpPort()); // add callback handler for sub request super.node.getObjectDataReplyHandler().addResponseCallbackHandler(uuid, this); this.sendChunk( 0, // first chunk this.fileId, this.owner, uuid, location); } } catch (Exception e) { logger.error("Failed to execute FilePushExchangeHandler. Message: " + e.getMessage(), e); } }