package tutor;
import java.net.*;
import java.io.*;
import java.util.*;
import java.applet.*;
//--------------------------------------------
/**
*
* This class represents a potential SoundDownload of a language sound.
* This class stores data about the process of attempting
* to download the sound resource from the Internet. The object
* will also be responsable for actually initiating the download
* process by opening a connection to the resource etc.
* This class may be run within a thread begun by the
* {@linkplain tutor.SoundDownloadManager} class.
*
* @see WebDownload
* @see "http://bumble.sf.net/lang/web/WebDownload.java"
* @author matth3wbishopyahoocom
*/
public class SoundDownload extends Object implements Task
{
//--------------------------------------------
/** The url of the sound file */
private String soundUrl;
//--------------------------------------------
/** A place to store the downloaded sound resource. if the file
* restrictions such as those imposed by an applet */
private String localFile;
//--------------------------------------------
/** The time at which the attempted download was begun */
private Date startTime;
//--------------------------------------------
/** The time at which the attempted download was terminated
* whether successfully or unsuccessfully */
private Date finishTime;
//--------------------------------------------
/** will store error messages produced when attempting the download
* of the data in the data file and in correcting that data. */
private StringBuffer errorMessage;
//--------------------------------------------
private String guessedContentType;
//--------------------------------------------
private String protocol;
//--------------------------------------------
private int httpResponseCode;
//--------------------------------------------
private String httpResponseMessage;
//--------------------------------------------
private String httpContentType;
//--------------------------------------------
private int httpContentLength;
//--------------------------------------------
private String httpContentEncoding;
//--------------------------------------------
private String failureCause;
//--------------------------------------------
private boolean wasSuccessful;
//--------------------------------------------
private boolean hasStarted;
//--------------------------------------------
private boolean hasFinished;
//--------------------------------------------
/** determines if the local file already exists */
private boolean localFileExists;
//--------------------------------------------
public static String NEWLINE = System.getProperty("line.separator");
//--------------------------------------------
public SoundDownload()
{
this.soundUrl = "";
this.localFile = "";
this.protocol = "";
this.guessedContentType = "";
this.httpContentType = "";
this.httpContentLength = 0;
this.httpContentEncoding = "";
this.httpResponseCode = 0;
this.httpResponseMessage = "";
this.failureCause = "";
this.errorMessage = new StringBuffer("");
this.hasStarted = false;
this.wasSuccessful = false;
this.hasFinished = false;
this.localFileExists = true;
this.soundUrl = new String("");
//this.startTime = new Date(0);
//this.finishTime = new Date(0);
} //-- constr: ()
//--------------------------------------------
public SoundDownload(String sSoundUrl)
{
this();
this.soundUrl = sSoundUrl;
}
//--------------------------------------------
public SoundDownload(String sSoundUrl, String sLocalFile)
{
this();
this.soundUrl = sSoundUrl;
this.localFile = sLocalFile;
File fLocalFile = new File(this.localFile);
if (!fLocalFile.exists())
{
this.localFileExists = false;
}
}
//--------------------------------------------
public Date getStartTime()
{
return this.startTime;
}
//--------------------------------------------
public Date getFinishTime()
{
return this.finishTime;
}
//--------------------------------------------
/** this is an alias for getDownloadDuration in order to
* comply with the {@linkplain tutor.Task} interface */
public long getWorkDuration()
{
return this.getDownloadDuration();
}
//--------------------------------------------
/** return the number of milliseconds taken to download the file. */
public long getDownloadDuration()
{
if (this.finishTime == null) { return 0; }
if (this.startTime == null) { return 0; }
return this.finishTime.getTime() - this.startTime.getTime();
}
//--------------------------------------------
/** this is an alias for getDownloadDurationInSeconds in order to
* comply with the {@linkplain tutor.Task} interface */
public float getWorkDurationInSeconds()
{
return this.getDownloadDurationInSeconds();
}
//--------------------------------------------
/** return the number of seconds taken to download the file. */
public float getDownloadDurationInSeconds()
{
if (this.finishTime == null) { return 0; }
if (this.startTime == null) { return 0; }
return (float)this.getDownloadDuration()/1000;
}
//--------------------------------------------
public String getSoundUrl()
{
return this.soundUrl;
}
//--------------------------------------------
public void setSoundUrl(String sSoundUrl)
{
this.soundUrl = sSoundUrl;
}
//--------------------------------------------
public boolean hasFinished()
{
if (this.finishTime == null)
{ return false; }
return true;
}
//--------------------------------------------
/** returns the canonical path to the file where the
* downloaded sound file will be or has been saved */
public String getLocalFilePath()
{
File ffLocalFile = new File(this.localFile);
String sFilePath;
try
{
sFilePath = ffLocalFile.getCanonicalPath();
}
catch (IOException e)
{
sFilePath = "";
}
return sFilePath;
}
//--------------------------------------------
/** returns the file (or path) where the downloaded sound
* resource will be (or has been) saved. */
public String getLocalFile()
{
return this.localFile;
}
//--------------------------------------------
public void setLocalFile(String sLocalFile)
{
this.localFile = sLocalFile;
File fLocalFile = new File(this.localFile);
if (!fLocalFile.exists())
{
this.localFileExists = false;
}
}
//--------------------------------------------
/* advises whether the attempted sound download was carried
* out successfully */
public boolean wasSuccessful()
{ return this.wasSuccessful; }
//--------------------------------------------
/* returns text describing the download result */
public String getResult()
{
if (this.hasStarted == false)
{ return "not started"; }
if (this.wasSuccessful)
{ return "success"; }
else
{ return "failure"; }
}
//--------------------------------------------
/** an alias for download, to comply with the Task interface */
public void begin()
{
this.download();
}
//--------------------------------------------
/** begin the download process. If this class is running in
* an applet context then all that will be required in some
* situations is to call the getAudioClip method of the
* applet. With most newish jre's this should play different
* file formats, but not mp3. If the applet is saving files
* to the local file system, then still the getAudioClip
* method should be sufficient */
public void download()
{
URL uSoundUrl;
URLConnection urlc;
HttpURLConnection httpc;
this.hasStarted = true;
this.startTime = new Date();
if (this.localFile.equals(""))
{
this.localFile =
this.soundUrl.substring(this.soundUrl.lastIndexOf('/')+1);
}
File fLocalFile = new File(this.localFile);
if (fLocalFile.exists())
{
this.localFileExists = true;
this.failureCause = "Local file '" + this.localFile + "' already exists";
this.wasSuccessful = false;
this.finishTime = new Date();
this.hasFinished = true;
return;
}
try
{
uSoundUrl = new URL(this.getSoundUrl());
this.protocol = uSoundUrl.getProtocol();
}
catch (MalformedURLException e)
{
this.failureCause = "Illegal Url";
this.errorMessage.append(e);
this.wasSuccessful = false;
this.finishTime = new Date();
this.hasFinished = true;
return;
} //-- try
try
{
urlc = uSoundUrl.openConnection();
}
catch (IOException e)
{
this.failureCause = "Couldnt create a connection";
this.errorMessage.append(e);
this.wasSuccessful = false;
this.finishTime = new Date();
this.hasFinished = true;
return;
} //-- try
try
{
urlc.connect();
}
catch (UnknownHostException e)
{
this.failureCause =
"The host '" + uSoundUrl.getHost() + "' could not be found";
this.errorMessage.append(e);
this.wasSuccessful = false;
this.finishTime = new Date();
this.hasFinished = true;
return;
}
catch (IOException e)
{
this.failureCause = "Couldnt establish a connection to URL";
//-- getMessage provides less information than e.toString
//--
//this.errorMessage.append(e.getMessage());
this.errorMessage.append(e.toString());
this.wasSuccessful = false;
this.finishTime = new Date();
this.hasFinished = true;
return;
} //-- try
/* cast the connection object so as to find out the precise cause
of any download problems */
if (uSoundUrl.getProtocol().equalsIgnoreCase("http"))
{
httpc = (HttpURLConnection)urlc;
try
{
this.httpResponseCode = httpc.getResponseCode();
this.httpResponseMessage = httpc.getResponseMessage();
}
catch (IOException e)
{
}
if (this.httpResponseCode == 404)
{
this.finishTime = new Date();
this.wasSuccessful = false;
this.hasFinished = true;
this.failureCause = "file not found on server";
this.errorMessage.append(
"Message from host '" + uSoundUrl.getHost() + "'" + NEWLINE +
this.httpResponseCode + " " + this.httpResponseMessage);
return;
}
if ((this.httpResponseCode < 200) || (this.httpResponseCode > 299))
{
this.finishTime = new Date();
this.wasSuccessful = false;
this.hasFinished = true;
this.failureCause = "server refused request";
this.errorMessage.append(NEWLINE +
"Server refused request : " + NEWLINE +
"Server response code : " + this.httpResponseCode + NEWLINE +
"Server response message: " + this.httpResponseMessage + NEWLINE);
return;
}
this.httpContentType = httpc.getContentType();
this.httpContentLength = httpc.getContentLength();
this.httpContentEncoding = httpc.getContentEncoding();
//-- check if the resource really is audio
if (!this.httpContentType.startsWith("audio"))
{
this.finishTime = new Date();
this.wasSuccessful = false;
this.hasFinished = true;
this.failureCause = "content is not audio";
return;
}
//-- the static method below may be useful to do further checks
//-- on the content type of the resource.
} //-- if is http
//URL u = new URL("http://www.java2s.com/binary.dat");
//URLConnection uc = u.openConnection();
//String contentType = uc.getContentType();
//int contentLength = uc.getContentLength();
if (this.httpContentLength == -1)
{
this.finishTime = new Date();
this.wasSuccessful = false;
this.hasFinished = true;
this.failureCause = "content length is -1";
return;
}
InputStream raw;
InputStream in;
try
{
raw = urlc.getInputStream();
in = new BufferedInputStream(raw);
}
catch (IOException e)
{
this.finishTime = new Date();
this.wasSuccessful = false;
this.hasFinished = true;
this.errorMessage.append(e);
this.failureCause = "couldnt open an input stream from the url";
return;
}
byte[] data = new byte[this.httpContentLength];
int bytesRead = 0;
int offset = 0;
while (offset < this.httpContentLength)
{
try
{
bytesRead = in.read(data, offset, data.length - offset);
}
catch (IOException e)
{
this.finishTime = new Date();
this.wasSuccessful = false;
this.hasFinished = true;
this.errorMessage.append(e);
this.failureCause = "error while reading from stream";
return;
}
if (bytesRead == -1)
{ break; }
offset += bytesRead;
} //-- while
try
{
in.close();
}
catch (IOException e)
{
this.finishTime = new Date();
this.wasSuccessful = false;
this.hasFinished = true;
this.errorMessage.append(e);
this.failureCause = "error trying to close the stream";
return;
}
if (offset != this.httpContentLength)
{
this.finishTime = new Date();
this.wasSuccessful = false;
this.hasFinished = true;
this.failureCause =
"Only read " + offset + " bytes; Expected " +
this.httpContentLength + " bytes";
return;
}
//String sfilename = u.getFile().substring(filename.lastIndexOf('/') + 1);
FileOutputStream out;
try
{
out = new FileOutputStream(this.localFile);
}
catch (FileNotFoundException e)
{
this.failureCause =
"The file '" + this.localFile + "' was not be found";
this.errorMessage.append(e);
this.wasSuccessful = false;
this.finishTime = new Date();
this.hasFinished = true;
return;
}
try
{
out.write(data);
out.flush();
out.close();
}
catch (IOException e)
{
this.failureCause =
"while writing data";
this.errorMessage.append(e);
this.wasSuccessful = false;
this.finishTime = new Date();
this.hasFinished = true;
return;
}
//System.out.println("trying to play...");
//this.soundObject.play();
this.finishTime = new Date();
this.wasSuccessful = true;
this.hasFinished = true;
} //-- method: download()
//--------------------------------------------
/** prints information such as the start time, the finish
* time, the duration and the success or failure of the
* download. */
public String printReport()
{
StringBuffer sbReturn = new StringBuffer("");
//-- if the download has not been attempted print a
//-- brief message and return
if (this.startTime == null)
{
return this.toString();
}
sbReturn.append("Result of the download:");
sbReturn.append(this.getResult() + NEWLINE);
sbReturn.append("Tried to get resource :");
sbReturn.append(this.getSoundUrl() + NEWLINE);
sbReturn.append("To local file :");
sbReturn.append(this.getLocalFile() + NEWLINE);
sbReturn.append("Which is the path :");
sbReturn.append(this.getLocalFilePath() + NEWLINE);
sbReturn.append("Download duration (s) :");
sbReturn.append((float)this.getDownloadDuration()/1000);
sbReturn.append(NEWLINE);
if (!this.failureCause.equals(""))
{
sbReturn.append("Cause of failure :");
sbReturn.append(this.failureCause);
sbReturn.append(NEWLINE);
}
sbReturn.append("Protocol used :");
sbReturn.append(this.protocol + NEWLINE);
sbReturn.append("Guessed Content Type :");
sbReturn.append(this.guessedContentType + NEWLINE);
sbReturn.append("Http Content Type :");
sbReturn.append(this.httpContentType + NEWLINE);
sbReturn.append("Http Content Length :");
sbReturn.append(this.httpContentLength + NEWLINE);
sbReturn.append("Http Content Encoding :");
sbReturn.append(this.httpContentEncoding + NEWLINE);
sbReturn.append("Start Time :");
sbReturn.append(this.startTime + NEWLINE);
sbReturn.append("Finish Time :");
sbReturn.append(this.finishTime + NEWLINE);
if (this.errorMessage.length() > 0)
{
sbReturn.append("Error Messages :");
sbReturn.append(NEWLINE);
sbReturn.append(this.errorMessage + NEWLINE);
}
sbReturn.append("");
sbReturn.append("");
return sbReturn.toString();
}
//--------------------------------------------
/** how is this different from toString */
public String print()
{
return this.toString();
}
//--------------------------------------------
/** a reasonably concise representation of the object */
public String toString()
{
StringBuffer sbReturn = new StringBuffer("");
if (!this.wasSuccessful)
{ sbReturn.append("! "); }
sbReturn.append("Sound Download (URL ");
sbReturn.append(this.getSoundUrl());
sbReturn.append(" --> " + this.localFile + ")" );
if (this.startTime == null)
{
sbReturn.append(" -not started- ");
return sbReturn.toString();
}
sbReturn.append(" ");
if (this.wasSuccessful)
{ sbReturn.append("successful "); }
else
{ sbReturn.append("failed "); }
sbReturn.append("-at- ");
sbReturn.append(this.startTime);
sbReturn.append(" ");
if (this.wasSuccessful)
{
sbReturn.append("[size: ");
sbReturn.append(this.httpContentLength);
sbReturn.append("] ");
sbReturn.append("[time: ");
sbReturn.append((float)this.getDownloadDuration()/1000);
sbReturn.append("s]");
}
else
{
sbReturn.append("[");
sbReturn.append(this.failureCause);
sbReturn.append("]");
}
sbReturn.append("");
//sbReturn.append(NEWLINE);
return sbReturn.toString();
} //-- method: toString
//--------------------------------------------
public static void main(String[] args) throws Exception
{
String sUsageMessage =
"usage: java SoundDownload [url] [local-file-name] \n\n" +
" downloads a sound file from the Internet or \n"+
" records the reason for the failure. If no local file \n" +
" name is given, then the url file name is used. \n";
String sTestUrl;
if (args.length == 0)
{
System.out.println(sUsageMessage);
System.exit(-1);
}
String sLocalFile = "";
if (args[0].equals("."))
{ sTestUrl = "http://bumble.sf.net/lengua/jp/so/doubutsu.wav"; }
else
{ sTestUrl = args[0]; }
if (args.length == 2)
{ sLocalFile = args[1]; }
SoundDownload sdTest = new SoundDownload(sTestUrl, sLocalFile);
//sdTest.setLocalFile("test.wav");
System.out.println(sdTest.toString());
System.out.println();
System.out.println("Starting download... ");
sdTest.download();
System.out.println("method: .toString()");
System.out.println(sdTest.toString());
System.out.println();
System.out.println("method: .printReport()");
System.out.println(sdTest.printReport());
AudioClip acTest;
acTest = Applet.newAudioClip((new File(sdTest.getLocalFile())).toURL());
if (acTest != null)
{
//System.out.println("trying to play sound ...");
//acTest.play();
}
else
{
System.out.println("no sound to play");
}
} //-- main()
} //-- SoundDownload class