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