Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2013 EMC Corporation. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* or in the "license" file accompanying this file. This file 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 com.emc.esu.api.rest;
import com.emc.esu.api.BufferSegment;
import com.emc.esu.api.Checksum;
import com.emc.esu.api.Checksum.Algorithm;
import com.emc.esu.api.EsuApi;
import com.emc.esu.api.EsuException;
import com.emc.esu.api.Extent;
import com.emc.esu.api.Identifier;
import com.emc.esu.api.MetadataList;
import com.emc.esu.api.ProgressListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
/**
* Helper class to download objects. For large transfers, the content
* generally needs to be transferred from the server in smaller chunks. This
* helper class reads an object's contents incrementally from the server and
* writes it to a file or stream.
*/
public class DownloadHelper {
private static final Logger l4j = Logger.getLogger(DownloadHelper.class);
private static final int DEFAULT_BUFFSIZE = 4096*1024; // 4MB
private EsuApi esu;
private BufferSegment buffer;
private long currentBytes;
private long totalBytes;
private boolean complete;
private boolean failed;
private Exception error;
private boolean closeStream;
private OutputStream stream;
private List listeners;
private boolean checksumming;
private Checksum checksum;
/**
* Creates a new download helper.
* @param esuApi the API connection object to use to communicate
* with the server.
* @param buffer the buffer to use for the transfers from the server. If
* null, a default 4MB buffer will be used.
*/
public DownloadHelper(EsuApi esuApi, byte[] buffer) {
this.esu = esuApi;
this.buffer = new BufferSegment(
buffer == null ? new byte[DEFAULT_BUFFSIZE] : buffer);
listeners = new ArrayList();
}
/**
* Downloads the given object's contents to a file.
* @param id the identifier of the object to download
* @param f the file to write the object's contents to.
*/
public void readObject( Identifier id, File f) {
OutputStream out;
try {
out = new FileOutputStream(f);
} catch (FileNotFoundException e) {
throw new EsuException("Error opening output file", e);
}
readObject(id, out, true);
}
/**
* Downloads the given object's contents to a stream.
* @param id the identifier of the object to download.
* @param stream the stream to write the object's contents to.
* @param closeStream specifies whether to close the stream after
* the transfer is complete. Defaults to true.
*/
public void readObject( Identifier id, OutputStream stream, boolean closeStream) {
this.currentBytes = 0;
this.complete = false;
this.failed = false;
this.error = null;
this.closeStream = closeStream;
this.stream = stream;
// Get the file size. Set to -1 if unknown.
MetadataList sMeta = this.esu.getAllMetadata(id).getMetadata();
if (sMeta.getMetadata("size") != null) {
String size = sMeta.getMetadata("size").getValue();
if (size != null && size.length() > 0) {
this.totalBytes = Long.parseLong(size);
} else {
this.totalBytes = -1;
}
} else {
this.totalBytes = -1;
}
// We need to know how big the object is to download it. Fail the
// transfer if we can't determine the object size.
if (this.totalBytes == -1) {
throw new EsuException("Failed to get object size");
}
if( checksumming ) {
try {
checksum = new Checksum( Algorithm.SHA0 );
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException( "Could not initialize SHA0 hash algorithm" );
}
}
// Loop, downloading chunks until the transfer is complete.
while (true) {
try {
Extent extent = null;
// Determine how much data to download. If we're at the last
// request in the transfer, only request as many bytes as needed
// to get to the end of the file.
if (currentBytes + buffer.getBuffer().length > totalBytes) {
// Would go past end of file. Request less bytes.
extent = new Extent(this.currentBytes, totalBytes
- currentBytes);
} else {
extent = new Extent(this.currentBytes,
buffer.getBuffer().length);
}
buffer.setSize((int) extent.getSize());
// Read data from the server.
byte[] obuffer = this.esu.readObject(id, extent, buffer.getBuffer(), checksum);
// See if they returned the buffer we're using. In some
// cases, this doesn't happen (when content length is not
// defined in the response).
if( obuffer != buffer.getBuffer() ) {
if( obuffer.length != extent.getSize() ) {
throw new EsuException( "Read size mismatch. " +
"Requested " + extent.getSize() +
" bytes but received " +
obuffer.length + " bytes" );
}
stream.write( obuffer, 0, obuffer.length );
} else {
// Write to the stream
stream.write(buffer.getBuffer(), buffer.getOffset(), buffer
.getSize());
}
// Update progress
this.progress(buffer.getSize());
// See if we're done.
if (this.currentBytes == this.totalBytes) {
if( checksumming && checksum.getExpectedValue() != null ) {
// Validate
if( !checksum.getExpectedValue().equals( checksum.toString() ) ) {
throw new EsuException("Checksum validation error. Expected " + checksum.getExpectedValue() + " but computed " + checksum.toString() );
} else {
l4j.info( "Checksum OK: " + checksum.getExpectedValue() );
}
}
this.complete();
return;
}
} catch (EsuException e) {
this.fail(e);
throw e;
} catch (IOException e) {
fail(e);
throw new EsuException("Error downloading file", e);
}
}
}
/**
* Gets the current number of bytes that have been downloaded.
* @return the current number of bytes downloaded.
*/
public long getCurrentBytes() {
return currentBytes;
}
/**
* Gets the total number of bytes to download.
* @return the total number of bytes to download.
*/
public long getTotalBytes() {
return totalBytes;
}
/**
* Returns true if the transfer has completed.
* @return true if the transfer has completed, false otherwise.
*/
public boolean isComplete() {
return this.complete;
}
/**
* Returns true if the transfer has failed.
* @return true if the transfer has failed, false otherwise.
*/
public boolean isFailed() {
return this.failed;
}
/**
* If the transfer has failed, return the error that caused the failure.
* @return the error that caused the transfer to fail.
*/
public Exception getError() {
return this.error;
}
/**
* Sets a listener to provide feedback on the transfer's progress.
* @param listener the listener to use for feedback. Set
* to null to disable progress notifications.
*/
public void addListener(ProgressListener listener) {
this.listeners.add(listener);
}
/////////////////////
// Private methods //
/////////////////////
/**
* Updates progress on the current transfer and notifies the listener if
* required.
* @param bytes the number of bytes transferred
*/
private void progress(long bytes) {
this.currentBytes += bytes;
for (Iterator i = listeners.iterator(); i.hasNext();) {
ProgressListener pl = i.next();
pl.onProgress(currentBytes, totalBytes);
}
}
/**
* Marks the current transfer as complete, closes the stream if required,
* and notifies the listener.
*/
private void complete() {
complete = true;
if (closeStream) {
try {
stream.close();
} catch (IOException e) {
// ignore
l4j.warn("Error closing output stream", e);
}
}
for (Iterator i = listeners.iterator(); i.hasNext();) {
ProgressListener pl = i.next();
pl.onComplete();
}
}
/**
* Fails the current transfer. Sets the failed flag and notifies the
* listener if required.
* @param e the error that caused the transfer to fail.
*/
private void fail(Exception e) {
this.failed = true;
this.error = e;
for (Iterator i = listeners.iterator(); i.hasNext();) {
ProgressListener pl = i.next();
pl.onError(e);
}
}
/**
* @param checksumming the checksumming to set
*/
public void setChecksumming(boolean checksumming) {
this.checksumming = checksumming;
}
/**
* @return the checksumming
*/
public boolean isChecksumming() {
return checksumming;
}
}