001/*
002 *  AliveURL.java
003 *  $Source: /cvsroot2/open/projects/WebARTS/ca/bc/webarts/tools/AliveURL.java,v $
004 *  $Revision: 563 $  $Date: 2012-11-03 19:28:37 -0700 (Sat, 03 Nov 2012) $  $Locker:  $
005 *  Copyright 2002 (C) WebARTS Design.   All rights reserved.
006 *
007 *  This program is free software; you can redistribute it and/or
008 *  modify it under the terms of the GNU General Public License
009 *  as published by the Free Software Foundation; either version 2
010 *  of the License, or any later version.
011 *
012 *  This program is distributed in the hope that it will be useful,
013 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
014 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 *  GNU General Public License for more details.
016 *
017 *  You should have received a copy of the GNU General Public License
018 *  along with this program; if not, write to the Free Software
019 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
020 */
021package ca.bc.webarts.tools;
022
023import java.awt.Toolkit;
024import java.io.File;
025import java.io.FileOutputStream;
026import java.io.IOException;
027import java.io.InputStream;
028import java.io.OutputStream;
029import java.io.PrintStream;
030import java.net.Authenticator;
031import java.net.HttpURLConnection;
032import java.net.MalformedURLException;
033import java.net.PasswordAuthentication;
034import java.net.URL;
035import java.net.URLConnection;
036import java.util.Date;
037import java.util.Properties;
038import java.util.Vector;
039
040import javax.mail.Address;
041import javax.mail.Message;
042import javax.mail.MessagingException;
043import javax.mail.SendFailedException;
044import javax.mail.Session;
045import javax.mail.Transport;
046import javax.mail.internet.InternetAddress;
047import javax.mail.internet.MimeMessage;
048
049import javax.sound.sampled.AudioFormat;
050import javax.sound.sampled.AudioInputStream;
051import javax.sound.sampled.AudioSystem;
052import javax.sound.sampled.DataLine;
053import javax.sound.sampled.LineUnavailableException;
054import javax.sound.sampled.SourceDataLine;
055import javax.sound.sampled.UnsupportedAudioFileException;
056
057// not necessary but saves headaches later if classes move
058import ca.bc.webarts.tools.StreamGobbler;
059
060//import com.jpeterson.x10.SendX10;
061
062
063/**
064 *  A simple commandline based app that periodically contacts some specified
065 *  URLs and confirms connectivity. It alarms if it cannot connect a specified
066 *  number of consequetive times. It also has
067 *  built in capability of calling/running an external script and or sending off
068 *  an email.<br><br>For Example... I use this as a watchdog for one of my
069 *  webservers.  The server is on a remote control power supply which allows me
070 *  to reboot the server if, for some reason, it has hung and fails this AliveURL
071 *  watchdog check 4 times in a row. It then sends off an email to my cell phone
072 *  to let me kknow there has been a problem.
073 *
074 * <pre>
075        Usage:
076          java -DproxySet=true -DproxyHost=YourProxyServerHostname
077               -DproxyPort=YourProxyServerPort
078               -DproxyUser=YourProxyUsernameIFNEEDED
079               -DproxyPassword=YourProxyUserPasswordIFNEEDED
080               -DnonProxyHosts=CommaSeperatedlistOfNonProxiedSites
081               ca.bc.webarts.tools.AliveURL [URL location 1] [URL location 2]...
082 </pre>
083 *
084 * @author     Tom Gutwin P.Eng
085 */
086class AliveURL extends Authenticator
087{
088  public Date currDate = new Date();
089  static int checkDelay = 300000; // 5 minutes
090  private static URL errorMusic = null;
091  private static File errorMusicFile = null;
092  private static String errorMusicUrlStr =
093      "http://www-bcg.bcg.ada.com/~gutwint/Carbrake.wav";
094  private static String errorMusicFileStr =
095      "/usr/lib/openoffice.org2.0/share/gallery/sounds/cow.wav";
096  private static boolean useURL = false;
097  Playback playback = null;
098  Toolkit tk = Toolkit.getDefaultToolkit();
099
100  public static final String DEFAULT_PROXY_SET = "false";
101  public static final String DEFAULT_PROXY_HOST = "bchrelay4";
102  public static final String DEFAULT_PROXY_PORT = "80";
103  public static final String DEFAULT_PROXY_NOPROXY = "";
104  /**
105   *  Constant Specifying that the logging output will go to System.out.
106   */
107  public final static short CONSOLE = 50;
108  /**
109   *  Constant Specifying that the logging output will go to a spec'd file.
110   */
111  public final static short FILE = 51;
112  /**
113   *  Constant Specifying that the logging output will go to a
114   *  spec'd OutputStream.
115   */
116  public final static short PIPE = 52;
117
118  /**
119   *  The Standard OutputStream.
120   */
121  private final static PrintStream STD_OUT = System.out;
122
123  /**
124   *  Description of the Field
125   */
126  static private String    logFileName_ = "AliveUrlLog.txt";
127  /**
128   *  Description of the Field
129   */
130  static private OutputStream userOut_ = STD_OUT;
131  /**
132   *  The stream that ALL logging ends upo getting directed to.
133   */
134  static private PrintStream logOut_ = null;
135  /**
136   *  Description of the Field
137   */
138  static private File      logFile_ = null;
139  /**
140   *  Description of the Field
141   */
142  static private short     outSpot_ = FILE;
143  /**
144   * A constant that tells us how many sequential errors to accept before
145   * calling the external Script.
146   **/
147  static private final short     ACCEPTABLE_NUMBER_ERRORS = 3;
148  /**
149   * An extra Delay after a script execution to wait before checking again.
150   **/
151  static private final int     EXTRA_DELAY_TIME = 600000; //10min
152  /**
153   * A class varthat tells us how many sequential errors have occured.
154   **/
155  static private short numSequentialErrors_ = 0;
156  /**
157   * This is the supervisor flag that toggles running the external script
158   * execution.
159   **/
160  static private boolean enableExecScript_ = false;
161  static private boolean enableJavaX10_ = true;
162  static private boolean externalScriptWasExecuted_ = false;
163  static private boolean areWePlayingMusic = true;
164  static private boolean areWeSendingEmail_ = true;
165  static private boolean areWeUsingProxy_ = false;
166  static private boolean useProxyAuthentication_ = true;
167  /**
168   * A class var to record and error message to print out if any of the
169   * validation checks on the properties fail.
170   **/
171  private static String errorMsg_ = "";
172
173  /** The email addr to send notifications to if a recycle happens **/
174  private static String emailTo_ = "tgutwin@webarts.bc.ca";
175
176  /** the class Proxy Username to authenticate with. **/
177  static private String proxyUsername_ = "YourProxyUserName";
178
179  /** the class Proxy Password to authenticate with. **/
180  static private String proxyPassword_ = "GetYourOwnPassword";
181
182  /** the Proxy hostname. **/
183  static private String proxyHost_ = DEFAULT_PROXY_HOST;
184
185  /** the Proxy port. **/
186  static private String proxyPort_ = DEFAULT_PROXY_PORT;
187
188  /** The X10 Commands to send to the X10 engine **/
189
190  private static String [] x10Cmd1_ = {"off","a","2"};
191  private static String [] x10Cmd2_ = {"on","a","2"};
192
193
194
195  /**
196   *
197   *  A simple/useless constructor for the sole purpose of providing the
198   *  Authenticator impl to the net authentication mechanism.  Both the passed
199   *  params can be null or "" - if they are the default class username and
200   *  pass are used.
201   *
202   * @param  String proxyUser is the usernamer to pass to the proxy
203   * @param  String proxyPass is the password to pass to the proxy
204   */
205  public AliveURL(String proxyUser, String proxyPass)
206  {
207    if (proxyUser != null && !proxyUser.equals(""))
208      proxyUsername_ = proxyUser;
209    if (proxyPass != null && !proxyPass.equals(""))
210      proxyPassword_ = proxyPass;
211  }
212
213
214  /**
215   *  Constructor for the AliveURL object
216   *
217   * @param  url  Description of the Parameter
218   */
219  public AliveURL(URL url)
220  {
221    if (url != null)
222    {
223      StringBuffer outStr = new StringBuffer();
224      try
225      {
226        int respCode = 200;
227        //initProxy();
228        currDate.setTime(System.currentTimeMillis());
229        outStr.append(currDate.toString());
230        outStr.append(" ");
231        outStr.append(url.getHost());
232        outStr.append(url.getPath());
233        Properties systemProperties = System.getProperties();
234        if (systemProperties.getProperty("http.proxyHost") != null &&
235            !systemProperties.getProperty("http.proxyHost").equals(""))
236        {
237          outStr.append(" proxy ");
238          outStr.append(systemProperties.getProperty("http.proxyHost"));
239          outStr.append(":");
240          outStr.append(systemProperties.getProperty("http.proxyPort"));
241        }
242        System.out.print(outStr.toString());
243        if (url.getProtocol().equals("http"))
244        {
245          HttpURLConnection connection =
246              (HttpURLConnection) url.openConnection();
247
248          respCode = connection.getResponseCode();
249          outStr.append(" --> ResponseCode: " );
250          outStr.append(respCode);
251          outStr.append(" = ");
252          outStr.append(connection.getResponseMessage());
253          System.out.print(" --> ResponseCode: " + respCode);
254          System.out.println(" = " + connection.getResponseMessage());
255          if (respCode == HttpURLConnection.HTTP_NOT_FOUND )
256          {
257            int headerCount = 1;
258            while (connection.getHeaderFieldKey(headerCount) != null)
259            {
260              System.out.print("     "+connection.getHeaderFieldKey(headerCount));
261              System.out.println(" = "+connection.getHeaderField(headerCount++));
262            }
263          }
264
265          if (respCode != 200)
266          {
267            if(areWePlayingMusic)
268            {
269              playErrorMusic();
270            }
271            numSequentialErrors_++;
272            if (numSequentialErrors_ > ACCEPTABLE_NUMBER_ERRORS)
273              callExternalScript();
274          }
275          else
276          {
277            unsetExternalScriptWasExecuted_();
278            numSequentialErrors_ = 0;
279          }
280        }
281        else
282        {
283          URLConnection connection = url.openConnection();
284          outStr.append(" --> Successful");
285          System.out.println(" --> Successful");
286          unsetExternalScriptWasExecuted_();
287          numSequentialErrors_ = 0;
288        }
289      }
290      catch (IOException ex)
291      {
292        String args = ex.getMessage();
293        numSequentialErrors_++;
294        System.out.println(" --> Unsuccessful ("+numSequentialErrors_+")");
295        System.out.println(args);
296        outStr.append(" --> Unsuccessful("+numSequentialErrors_+")");
297        outStr.append(args);
298        if(areWePlayingMusic)
299        {
300          playErrorMusic();
301          }
302        if (numSequentialErrors_ > ACCEPTABLE_NUMBER_ERRORS)
303          callExternalScript();
304      }
305      logEntry(outStr.toString());
306    }
307  }
308
309
310  /**
311   * Sets the to email address for email notice of the no-connection.
312   *
313   * @param emailTo the email addr to use
314   **/
315  public void setEmailTo(String emailTo)
316  {
317    this.emailTo_ = emailTo;
318  }
319
320
321  /**
322   * emailTo_ Getter.
323   *
324   * @return the emailTo_ field.
325   **/
326  public String getEmailTo()
327  {
328    return emailTo_;
329  }
330
331
332/**
333  * The public set method to set the enableExecScript_ class field.
334  *
335  * @param enableExecScript is the value to use to set the class field to.
336  *
337  **/
338public void setEnableExecScript(boolean enableExecScript)
339{
340  this.enableExecScript_ = enableExecScript;
341}
342
343
344/**
345  * The public get method to return the enableExecScript_ class field.
346  *
347  * @return  the class field: enableExecScript_
348  *
349  **/
350public boolean getEnableExecScript()
351{
352  return enableExecScript_;
353}
354
355
356public void setExternalScriptWasExecuted_()
357{
358  this.externalScriptWasExecuted_ = true;
359}
360
361
362public void unsetExternalScriptWasExecuted_()
363{
364  this.externalScriptWasExecuted_ = false;
365}
366
367
368public void setExternalScriptWasExecuted_(boolean externalScriptWasExecuted_)
369{
370  this.externalScriptWasExecuted_ = externalScriptWasExecuted_;
371}
372
373
374public boolean getExternalScriptWasExecuted_()
375{
376  return externalScriptWasExecuted_;
377}
378
379
380  /**
381   *  Does the gruntwork to get the proxy properties set.
382   **/
383
384  public static void initProxy()
385  {
386    // Set up the proxy settings if needed
387    Properties sysProps = System.getProperties();
388    String tmpUseproxy  = sysProps.getProperty("proxySet");
389    // System.out.println("tmpUseproxy="+tmpUseproxy);
390    if (tmpUseproxy != null && !tmpUseproxy.equals("null") && !tmpUseproxy.equals(""))
391      areWeUsingProxy_ = (tmpUseproxy.toLowerCase().equals("true")?true:false);
392
393
394    if (areWeUsingProxy_)
395    {
396      System.out.println("Initializing the proxy settings");
397      // check if the user had something defined in the Sys Props via the cmdline.
398      String tmpUser  = sysProps.getProperty("http.proxyUser");
399      String tmpPass  = sysProps.getProperty("http.proxyPassword");
400      String tmpHost  = sysProps.getProperty("http.proxyHost");
401      String tmpPort  = sysProps.getProperty("http.proxyPort");
402
403      if (tmpUser != null && !tmpUser.equals(""))
404        proxyUsername_ = tmpUser;
405      if (tmpPass != null && !tmpPass.equals(""))
406        proxyPassword_ = tmpPass;
407      if (tmpHost != null && !tmpHost.equals(""))
408        proxyHost_ = tmpHost;
409      if (tmpPort != null && !tmpPort.equals(""))
410        proxyPort_ = tmpHost;
411
412      if (useProxyAuthentication_)
413      {
414        System.out.println("Authenticating the proxy.");
415        Authenticator.setDefault(new AliveURL(proxyUsername_, proxyPassword_));
416      }
417      sysProps.put("proxySet", "true");
418      sysProps.put("http.proxyHost", proxyHost_);
419      sysProps.put("http.proxyPort", proxyPort_);
420      sysProps.put("noProxy",
421        "www-bcg.bcg.ada.com,*.ada.com,149.154.64.245,149.154.64.245:8080");
422    }
423
424  }
425
426
427   /**
428   *  Impl for Authenticator so an authorizing proxy will work.
429   **/
430
431  protected PasswordAuthentication getPasswordAuthentication()
432  {
433    return new PasswordAuthentication(
434        proxyUsername_, proxyPassword_.toCharArray());
435  }
436
437
438  /**
439   *  Execs an external script/application when an error occurs..
440   */
441  private void callExternalScript()
442  {
443    boolean testingOnly = false;
444
445    // 1st cycle the server power OFF
446    String cmdScript = "nice.exe";
447    Vector v = new Vector();
448    v.add("/D");
449    v.add("G:\\apps\\x10\\X10_cmd.cmd");
450    v.add("B2");
451    v.add("OFF");
452    if (enableExecScript_)
453    {
454      executeNativeApp(cmdScript, v);
455      setExternalScriptWasExecuted_();
456    }
457    if (enableJavaX10_)
458    {
459      //System.out.println("Calling Java X10 Command Off");
460      //SendX10 sendX10 = new SendX10("com.jpeterson.x10.module.CM17A");
461      //sendX10.transmit(0, x10Cmd1_);
462      String x10HouseCode = "B";
463      String x10DeviceNumber = "1";
464      String x10Command = "off";
465      if (!testingOnly) (new ca.bc.webarts.tools.X10FireCracker()).sendX10Command(x10HouseCode, x10DeviceNumber, x10Command );
466      if (areWeSendingEmail_)
467        sendAnEmail(emailTo_, "AliveURL Notification", "AliveURL Sent X10 Command ( "+
468                         x10HouseCode + x10DeviceNumber +" "+x10Command +") - "+(new Date()).toString());
469      setExternalScriptWasExecuted_();
470    }
471
472    // wait for the command to execute
473    mySleep(15000);
474
475    // The cycle the server power back On
476    v= new Vector();
477    v.add("/D");
478    v.add("G:\\apps\\x10\\X10_cmd.cmd");
479    v.add("B2");
480    v.add("ON");
481    if (enableExecScript_)
482      executeNativeApp(cmdScript, v);
483    if (enableJavaX10_)
484    {
485      try
486      {
487        //System.out.println("Calling Java X10 Command On");
488        //SendX10 sendX10 = new SendX10("com.jpeterson.x10.module.CM17A");
489        //sendX10.transmit(0, x10Cmd2_);
490        String x10HouseCode = "B";
491        String x10DeviceNumber = "1";
492        String x10Command = "on";
493        if (!testingOnly) (new ca.bc.webarts.tools.X10FireCracker()).sendX10Command(x10HouseCode, x10DeviceNumber, x10Command );
494        if (areWeSendingEmail_)
495          sendAnEmail(emailTo_, "AliveURL Notification", "AliveURL Sent X10 Command ( "+
496                         x10HouseCode + x10DeviceNumber +" "+x10Command +") - "+(new Date()).toString());
497      }
498      catch (java.lang.UnsatisfiedLinkError x10Ex)
499      {
500        System.out.println("Exception thrown... trying again after 60 seconds.");
501        // wait for the command to execute
502        mySleep(60000);
503        //SendX10 sendX10 = new SendX10("com.jpeterson.x10.module.CM17A");
504        //sendX10.transmit(0, x10Cmd2_);
505        String x10HouseCode = "A";
506        String x10DeviceNumber = "2";
507        String x10Command = "off";
508        if (!testingOnly) (new ca.bc.webarts.tools.X10FireCracker()).sendX10Command(x10HouseCode, x10DeviceNumber, x10Command );
509        if (areWeSendingEmail_)
510          sendAnEmail(emailTo_, "AliveURL Notification", "AliveURL Sent X10 Command ( "+
511                         x10HouseCode + x10DeviceNumber +" "+x10Command +") - "+(new Date()).toString());
512
513      }
514    }
515  }
516
517
518  /**
519   * Executes the Specified Native OS application with the provided commandline
520   * parameters. This method blocks until the Executed app is complete. It also
521   * cleans up its sub-process and garbage collects.
522   *
523   * @param executableLocation is the path to the executable to run
524   *
525   * @param appParms and extra commandline parameters to tag onto the end of the
526   *                 commandline that gets executed.
527   *
528   * @return returns the return code from the executed app/process
529   *
530   * @see StreamGobbler
531   * @see java.lang.Runtime#getRuntime
532   **/
533  private static int executeNativeApp(String executableLocation,
534                                      Vector appParms)
535  {
536    int retVal = -1;
537    int cmdParms = 0;
538    if (appParms != null)
539      cmdParms = appParms.size();
540    String [] cmds = new String [cmdParms+1];
541    cmds[0] = executableLocation;
542    System.out.print("AutoUpdateApp: Executing: "+ cmds[0]);
543    for (int i=1; i <= cmdParms; i++)
544    {
545      cmds[i] = (String) appParms.elementAt(i-1);
546      System.out.print(" " + cmds[i]);
547    }
548    System.out.println("");
549
550    // Start the app... This starts a new process
551    try
552    {
553      Runtime runtime = Runtime.getRuntime();
554      Process p = runtime.exec(cmds);
555
556      // capture any output we get
557      // any error message?
558      StreamGobbler errorGobbler = new
559        StreamGobbler(p.getErrorStream(), "RMT APP ERR:");
560
561      // any output?
562      StreamGobbler outputGobbler = new
563        StreamGobbler(p.getInputStream(), "RMT APP OUT:");
564
565      // kick them off
566      errorGobbler.start();
567      outputGobbler.start();
568
569      // now wait for the process to end
570      try
571      {
572        p.waitFor();
573      }
574      catch (InterruptedException intEx)
575      {
576        // no biggie
577      }
578      retVal = p.exitValue();
579      errorGobbler.finishedGobbling_ = true;
580      outputGobbler.finishedGobbling_ = true;
581      p.destroy();
582      p = null;
583      runtime.gc();
584    }
585    catch (IOException ioEx)
586    {
587      errorMsg_ = "ERROR: An IO exception occured while attempting " +
588        "execution of the " + executableLocation + " application.";
589    }
590    catch (SecurityException securityEx)
591    {
592      errorMsg_ = "ERROR: A Java Security Manager is in use and is " +
593        "restricting execution of the " + executableLocation + " application.";
594    }
595
596    return retVal;
597  }
598
599
600  /**
601   * Send a cycle email out to the existing class email addr.
602    **/
603  private void sendAnEmail()
604  {
605    sendAnEmail(getEmailTo());
606  }
607
608
609  /**
610   * Send a cycle email out.
611    **/
612  private void sendAnEmail(String to)
613  {
614    sendAnEmail(to, "AliveURL Notification", "X10 Command Sent - "+currDate.toString());
615  }
616
617
618  /**
619   * Send a cycle email out.
620    **/
621  private void sendAnEmail(String to, String subjectToSend, String msgToSend)
622  {
623    boolean debug = false;
624    //String to = "tgutwin_sms@webarts.bc.ca";
625    //String to = "tgutwin@webarts.bc.ca";
626    String from = "tgutwin@webarts.bc.ca";
627    String host = "aurora1.webarts.bc.ca";
628    String msgText = msgToSend;
629
630    // create some properties and get the default Session
631    Properties props = new Properties();
632    props.put("mail.smtp.host", host);
633    if (debug)
634    {
635      props.put("mail.debug", "true");
636    }
637
638    Session session = Session.getDefaultInstance(props, null);
639    session.setDebug(debug);
640
641    try
642    {
643      // create a message
644      Message msg = new MimeMessage(session);
645      msg.setFrom(new InternetAddress(from));
646      InternetAddress[] address = {new InternetAddress(to)};
647      msg.setRecipients(Message.RecipientType.TO, address);
648      msg.setSubject(subjectToSend);
649      msg.setSentDate(new Date());
650      // If the desired charset is known, you can use
651      // setText(text, charset)
652      msg.setText(msgText);
653
654      Transport.send(msg);
655    }
656    catch (MessagingException mex)
657    {
658      System.out.println("\n--Exception handling in AliveURL.java");
659
660      mex.printStackTrace();
661      System.out.println();
662      Exception ex = mex;
663      do
664      {
665        if (ex instanceof SendFailedException)
666        {
667          SendFailedException sfex = (SendFailedException) ex;
668          Address[] invalid = sfex.getInvalidAddresses();
669          if (invalid != null)
670          {
671            System.out.println("    ** Invalid Addresses");
672            if (invalid != null)
673            {
674              for (int i = 0; i < invalid.length; i++)
675              {
676                System.out.println("         " + invalid[i]);
677              }
678            }
679          }
680          Address[] validUnsent = sfex.getValidUnsentAddresses();
681          if (validUnsent != null)
682          {
683            System.out.println("    ** ValidUnsent Addresses");
684            if (validUnsent != null)
685            {
686              for (int i = 0; i < validUnsent.length; i++)
687              {
688                System.out.println("         " + validUnsent[i]);
689              }
690            }
691          }
692          Address[] validSent = sfex.getValidSentAddresses();
693          if (validSent != null)
694          {
695            System.out.println("    ** ValidSent Addresses");
696            if (validSent != null)
697            {
698              for (int i = 0; i < validSent.length; i++)
699              {
700                System.out.println("         " + validSent[i]);
701              }
702            }
703          }
704        }
705        System.out.println();
706      } while ((ex = ((MessagingException) ex).getNextException())
707           != null);
708    }
709
710  }
711
712  /**
713   *  Initializes the logOut_ Stream based on the outSpot specifired by the user.
714   */
715  static private void initLogOut()
716  {
717    switch (outSpot_)
718    {
719      case FILE:
720        if (logFile_ != null)
721        {
722          try
723          {
724            logOut_ = new PrintStream(new FileOutputStream(logFile_), true);
725          }
726          catch (IOException ioEx)
727          {
728            STD_OUT.println("Error Creating Logfile:\n  " + ioEx.getMessage());
729            outSpot_ = CONSOLE;
730            initLogOut();
731          }
732        }
733        else
734        {
735          outSpot_ = CONSOLE;
736          initLogOut();
737        }
738        break;
739      case PIPE:
740        logOut_ = new PrintStream(userOut_, true);
741        break;
742      default: // default is CONSOLE
743        logOut_ = new PrintStream(STD_OUT, true);
744    }
745  }
746
747  /**
748   *  Generic uncategorized log entry.
749   *
750   * @param  value  The String to dump into the Log.
751   */
752  static private void logEntry(String value)
753  {
754    if (logOut_ != null )
755    {
756      //value = createCurrentTimeStamp() + ":" + msgSpacing_ + value;
757      logOut_.println(value);
758    }
759  }
760
761
762  /**  Plays the error music file */
763  private void playErrorMusic()
764  {
765    tk.beep();
766    tk.beep();
767    if (errorMusic != null)
768    {
769      //  System.out.println(" --> Nice Music URL");
770      // play error music
771      playback = new Playback(errorMusic);
772      playback.start();
773    }
774    else if (errorMusicFile != null)
775    {
776      //  System.out.println(" --> Nice Music File");
777      // play error music
778      playback = new Playback(errorMusicFile);
779      playback.start();
780    }
781  }
782
783
784  /**
785   *  A method to simply abstract the Try/Catch required to put the current
786   *  thread to sleep for the specified time in ms.
787   *
788   * @param  waitTime  the sleep time in milli seconds (ms).
789   * @return           boolean value specifying if the sleep completed (true) or
790   *      was interupted (false).
791   */
792  private static boolean mySleep(long waitTime)
793  {
794    boolean retVal = true;
795
796    /*
797     *  BLOCK for the spec'd time
798     */
799    try
800    {
801      Thread.sleep(waitTime);
802    }
803    catch (InterruptedException iex)
804    {
805      retVal = false;
806    }
807    return retVal;
808  }
809
810
811  /**
812   *  The main program for the AliveURL class
813   *
814   * @param  args  The command line arguments
815   */
816  public static void main(String[] args)
817  {
818    String emailAddr = null;
819    try
820    {
821      if (args.length > 0)
822      {
823        short options = 0;
824        logFile_ = new File(logFileName_);
825        initLogOut();
826
827        // set up the proxy ONCE here for evermore.
828        AliveURL.initProxy();
829
830
831        while (true)
832        {
833          emailAddr = null;
834          if (args[0].toUpperCase().startsWith("-M"))
835          {
836            // A music file was spec'd
837            options = 1;
838            if (args[0].substring(2).startsWith("http") ||
839                args[0].substring(2).startsWith("ftp") ||
840                args[0].substring(2).startsWith("file:/"))
841            {
842              try
843              {
844                errorMusic = new URL(args[0].substring(2));
845                errorMusicFile = null;
846                //  System.out.println("Got Our Error Music URL: " +
847                //  errorMusic.toString());
848              }
849              catch (MalformedURLException badUrl)
850              {
851                System.out.println("Can't Get ERROR MUSIC URL");
852                errorMusic = null;
853              }
854            }
855            else
856            {
857              // assume it is a file path
858              try
859              {
860                errorMusicFile = new File(args[0].substring(2));
861              }
862              catch (NullPointerException badUrl)
863              {
864                System.out.println("Can't Get ERROR MUSIC FILE");
865                errorMusicFile = null;
866              }
867            }
868          }
869          else if (args[0].toUpperCase().startsWith("-E"))
870          {
871            options = 1;
872            emailAddr = args[0].substring(2);
873          }
874          else if (args.length >1 && args[1].toUpperCase().startsWith("-M"))
875          {
876            // A music file was spec'd
877            options = 2;
878            if (args[1].substring(2).startsWith("http") ||
879                args[1].substring(2).startsWith("ftp") ||
880                args[1].substring(2).startsWith("file:/"))
881            {
882              try
883              {
884                errorMusic = new URL(args[1].substring(2));
885                errorMusicFile = null;
886                //  System.out.println("Got Our Error Music URL: " +
887                //  errorMusic.toString());
888              }
889              catch (MalformedURLException badUrl)
890              {
891                System.out.println("Can't Get ERROR MUSIC URL");
892                errorMusic = null;
893              }
894            }
895            else
896            {
897              // assume it is a file path
898              try
899              {
900                errorMusicFile = new File(args[1].substring(2));
901              }
902              catch (NullPointerException badUrl)
903              {
904                System.out.println("Can't Get ERROR MUSIC FILE");
905                errorMusicFile = null;
906              }
907            }
908          }
909          else if (args.length >1 && args[1].toUpperCase().startsWith("-E"))
910          {
911            options = 2;
912            emailAddr = args[1].substring(2);
913          }
914          else
915          {
916            // it was not the error music... so use it as a URL to check
917            try
918            {
919              if (useURL)
920              {
921                errorMusic = new URL(errorMusicUrlStr);
922              }
923              else
924              {
925                errorMusicFile = new File(errorMusicFileStr);
926              }
927              // System.out.println("Got Our Error Music URL.");
928            }
929            catch (MalformedURLException badUrl)
930            {
931              System.out.println("Can't Get ERROR MUSIC URL");
932              errorMusic = null;
933            }
934            catch (NullPointerException badUrl)
935            {
936              System.out.println("Can't Get ERROR MUSIC FILE");
937              errorMusicFile = null;
938            }
939          }
940
941
942          // now do the check!
943          int extraDelay = 0;
944          AliveURL checker = null;
945          URL url = null;
946          for (int i = options; i < args.length; i++)
947          {
948            url = new URL(args[i]);
949            checker = new AliveURL(url);
950            if (checker.getExternalScriptWasExecuted_() )
951              // add an extra 10 minutes before checking again
952              extraDelay = EXTRA_DELAY_TIME;
953          }
954          System.out.println("----------------------------------------"+
955                             (extraDelay>0?" ExtraDelay="+extraDelay/1000:""));
956          mySleep(checkDelay + extraDelay);
957          if (extraDelay>0 && checker != null)
958          {
959            if (emailAddr != null)
960              checker.sendAnEmail(emailAddr, "AliveURL Notification", "AliveURL Resuming Checking - "+(new Date()).toString());
961            else if (areWeSendingEmail_)
962              checker.sendAnEmail(emailTo_, "AliveURL Notification", "AliveURL Resuming Checking - "+(new Date()).toString());
963            checker.unsetExternalScriptWasExecuted_();
964          }
965          extraDelay = 0;
966          checker = null;
967          System.gc();
968        }
969      }
970      else
971      {
972        URL url = new URL("http://www.webarts.bc.ca");
973        while (true)
974        {
975          try
976          {
977            if (useURL)
978            {
979              errorMusic = new URL(errorMusicUrlStr);
980            }
981            else
982            {
983              errorMusicFile = new File(errorMusicFileStr);
984            }
985            //  System.out.println("Got Our Error Music URL.");
986          }
987          catch (MalformedURLException badUrl)
988          {
989            System.out.println("Can't Get ERROR MUSIC URL");
990            errorMusic = null;
991          }
992          catch (NullPointerException badUrl)
993          {
994            System.out.println("Can't Get ERROR MUSIC FILE");
995            errorMusicFile = null;
996          }
997          AliveURL checker = new AliveURL(url);
998          int extraDelay = 0;
999          if (checker.getExternalScriptWasExecuted_() )
1000            extraDelay = EXTRA_DELAY_TIME; // add an extra 10 minutes before checking again
1001          System.out.println("----------------------------------------");
1002          mySleep(checkDelay+extraDelay);
1003          if (extraDelay>0  && checker != null)
1004          {
1005            if (emailAddr != null)
1006              checker.sendAnEmail(emailAddr, "AliveURL Notification", "AliveURL Resuming Checking - "+(new Date()).toString());
1007            else if (areWeSendingEmail_)
1008              checker.sendAnEmail(emailTo_, "AliveURL Notification", "AliveURL Resuming Checking - "+(new Date()).toString());
1009            checker.unsetExternalScriptWasExecuted_();
1010          }
1011          checker = null;
1012          extraDelay = 0;
1013          System.gc();
1014
1015        }
1016      }
1017    }
1018    catch (MalformedURLException ex)
1019    {
1020      String msg = ex.getMessage();
1021      System.out.println(msg);
1022    }
1023  }
1024
1025/*
1026  private static void initProxy2()
1027  {
1028
1029    boolean httpEnabled = areWeUsingProxy_;
1030    Properties sysProps = System.getProperties();
1031    if (!httpEnabled)
1032    {
1033      sysProps.remove("proxySet");
1034      sysProps.remove("proxyHost");
1035      sysProps.remove("proxyPort");
1036      sysProps.remove("http.proxyHost");
1037      sysProps.remove("http.proxyPort");
1038      sysProps.remove("http.nonProxyHosts");
1039      Authenticator.setDefault(null);
1040    }
1041    else
1042    {
1043      if (sysProps.getProperty("http.proxySet") == null ||
1044          sysProps.getProperty("http.proxySet").equals(""))
1045        System.setProperty("http.proxySet", DEFAULT_PROXY_SET);
1046
1047      if (sysProps.getProperty("http.proxyHost") == null ||
1048          sysProps.getProperty("http.proxyHost").equals(""))
1049        System.setProperty("http.proxyHost", DEFAULT_PROXY_HOST);
1050
1051      if (sysProps.getProperty("http.proxyPort") == null ||
1052          sysProps.getProperty("http.proxyPort").equals(""))
1053        System.setProperty("http.proxyPort", DEFAULT_PROXY_PORT);
1054
1055      if (sysProps.getProperty("http.nonProxyHosts") == null ||
1056          sysProps.getProperty("http.nonProxyHosts").equals(""))
1057        System.setProperty("http.nonProxyHosts", DEFAULT_PROXY_NOPROXY);
1058
1059      // set proxy authentication
1060      String username = sysProps.getProperty("http.proxyUser");
1061      String password = sysProps.getProperty("http.proxyPassword");
1062      if (username == null ||
1063          username.equals(""))
1064        username = "";
1065
1066      if (password == null ||
1067          password.equals(""))
1068        password = "";
1069
1070      if(username == null || username.length()==0)
1071      {
1072        Authenticator.setDefault(new FirewallAuthenticator(null));
1073      }
1074      else
1075      {
1076        PasswordAuthentication pw = new PasswordAuthentication(
1077          username,password.toCharArray()
1078        );
1079        Authenticator.setDefault(new FirewallAuthenticator(pw));
1080      }
1081    }
1082  }
1083
1084
1085  // FirewallAuthenticator class
1086  static class FirewallAuthenticator extends Authenticator
1087  {
1088    PasswordAuthentication pw;
1089
1090    public FirewallAuthenticator(PasswordAuthentication pw)
1091    {
1092      this.pw = pw;
1093    }
1094
1095    protected PasswordAuthentication getPasswordAuthentication()
1096    {
1097      return pw;
1098    }
1099  }
1100*/
1101
1102  /**
1103   *  Write data to the OutputChannel.
1104   *
1105   * @author     unknowntgutwin
1106   */
1107  public class Playback implements Runnable
1108  {
1109
1110    final static int BUFFER_SIZE = 16384;
1111    SourceDataLine line;
1112    Thread thread;
1113    URL urlToPlay = null;
1114    File fileToPlay = null;
1115    AudioInputStream audioInputStream = null;
1116
1117
1118    /**
1119     *  Constructor for the Playback object
1120     *
1121     * @param  url  Description of the Parameter
1122     */
1123    public Playback(URL url)
1124    {
1125      urlToPlay = url;
1126    }
1127
1128
1129    /**
1130     *  Constructor for the Playback object
1131     *
1132     * @param  f  Description of the Parameter
1133     */
1134    public Playback(File f)
1135    {
1136      fileToPlay = f;
1137    }
1138
1139
1140    /**
1141     *  Description of the Method
1142     *
1143     * @param  msg  Description of the Parameter
1144     */
1145    private void reportStatus(String msg)
1146    {
1147      if (msg != null)
1148      {
1149        System.out.println(msg);
1150      }
1151    }
1152
1153
1154    /**
1155     *  Description of the Method
1156     *
1157     * @param  file  Description of the Parameter
1158     */
1159    public void createAudioInputStream(File file)
1160    {
1161      if (file != null && file.isFile())
1162      {
1163        try
1164        {
1165          createAudioInputStream(file.toURL());
1166        }
1167        catch (MalformedURLException ex)
1168        {
1169          audioInputStream = null;
1170        }
1171      }
1172      else
1173      {
1174        reportStatus("Audio file required.");
1175      }
1176    }
1177
1178
1179    /**
1180     *  Description of the Method
1181     *
1182     * @param  url  Description of the Parameter
1183     */
1184    public void createAudioInputStream(URL url)
1185    {
1186      if (url != null)
1187      {
1188        try
1189        {
1190          //   reportStatus("\nLoading AudioURL Stream " + url);
1191          InputStream urlStream = url.openStream();
1192          //   reportStatus("   InputStream is " + (urlStream==null?"null":"Valid"));
1193          audioInputStream = AudioSystem.getAudioInputStream(urlStream);
1194        }
1195        catch (UnsupportedAudioFileException ex)
1196        {
1197          reportStatus(ex.toString());
1198        }
1199        catch (IOException ex)
1200        {
1201          ex.printStackTrace();
1202        }
1203      }
1204      else
1205      {
1206        reportStatus("Audio file required.");
1207      }
1208    }
1209
1210
1211    /**  Description of the Method */
1212    public void start()
1213    {
1214      thread = new Thread(this);
1215      thread.setName("Playback");
1216      thread.start();
1217    }
1218
1219
1220    /**  Description of the Method */
1221    public void stop()
1222    {
1223      thread = null;
1224    }
1225
1226
1227    /**
1228     *  Description of the Method
1229     *
1230     * @param  message  Description of the Parameter
1231     */
1232    private void shutDown(String message)
1233    {
1234      if (message != null)
1235      {
1236        System.err.println(message);
1237      }
1238    }
1239
1240
1241    /**  Main processing method for the Playback object */
1242    public void run()
1243    {
1244
1245      // reload the file if loaded by file
1246      if (fileToPlay != null)
1247      {
1248        createAudioInputStream(fileToPlay);
1249      }
1250
1251      // reload the file if loaded by file
1252      if (urlToPlay != null)
1253      {
1254        createAudioInputStream(urlToPlay);
1255      }
1256
1257      // make sure we have something to play
1258      if (audioInputStream == null)
1259      {
1260        shutDown("No loaded audio to play back");
1261        return;
1262      }
1263      // reset to the beginnning of the stream
1264      try
1265      {
1266        audioInputStream.reset();
1267      }
1268      catch (Exception e)
1269      {
1270        shutDown("Unable to reset the stream\n" + e);
1271        return;
1272      }
1273
1274      // get an AudioInputStream of the desired format for playback
1275      AudioFormat format = audioInputStream.getFormat();
1276      AudioInputStream playbackInputStream = AudioSystem.getAudioInputStream(format, audioInputStream);
1277
1278      if (playbackInputStream == null)
1279      {
1280        shutDown("Unable to convert stream of format " + audioInputStream + " to format " + format);
1281        return;
1282      }
1283
1284      // define the required attributes for our line,
1285      // and make sure a compatible line is supported.
1286
1287      DataLine.Info info = new DataLine.Info(SourceDataLine.class,
1288          format);
1289      if (!AudioSystem.isLineSupported(info))
1290      {
1291        shutDown("Line matching " + info + " not supported.");
1292        return;
1293      }
1294
1295      // get and open the source data line for playback.
1296
1297      try
1298      {
1299        line = (SourceDataLine) AudioSystem.getLine(info);
1300        line.open(format, BUFFER_SIZE);
1301      }
1302      catch (LineUnavailableException ex)
1303      {
1304        shutDown("Unable to open the line: " + ex);
1305        return;
1306      }
1307
1308      // play back the captured audio data
1309
1310      int frameSizeInBytes = format.getFrameSize();
1311      int bufferLengthInFrames = line.getBufferSize() / 8;
1312      int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
1313      byte[] data = new byte[bufferLengthInBytes];
1314      int numBytesRead = 0;
1315
1316      // start the source data line
1317      line.start();
1318
1319      while (thread != null)
1320      {
1321        try
1322        {
1323          if ((numBytesRead = playbackInputStream.read(data)) == -1)
1324          {
1325            break;
1326          }
1327          int numBytesRemaining = numBytesRead;
1328          while (numBytesRemaining > 0)
1329          {
1330            numBytesRemaining -= line.write(data, 0, numBytesRemaining);
1331          }
1332        }
1333        catch (Exception e)
1334        {
1335          shutDown("Error during playback: " + e);
1336          break;
1337        }
1338      }
1339      // we reached the end of the stream.  let the data play out, then
1340      // stop and close the line.
1341      if (thread != null)
1342      {
1343        line.drain();
1344      }
1345      line.stop();
1346      line.close();
1347      line = null;
1348      shutDown(null);
1349    }
1350
1351  }
1352  // End class Playback
1353}
1354
1355