home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / VCAFE.3.0A / Sample.bin / WLAUtil.java < prev    next >
Text File  |  1998-11-05  |  20KB  |  545 lines

  1. // Copyright (c) 1997, 1998 Symantec, Inc. All Rights Reserved.
  2.  
  3. // Static utility routines for the web log analyzer
  4.  
  5. import java.awt.Rectangle;
  6. import java.awt.Component;
  7. import java.awt.Window;
  8. import java.awt.Frame;
  9. import java.awt.Dialog;
  10. import java.awt.TextField;
  11. import java.util.Date;
  12. import java.text.DateFormat;
  13. import java.text.SimpleDateFormat;
  14. /*
  15. This class encapsulates miscellaneous static utility routines used by the 
  16. web log analyzer.
  17. */
  18. final class WLAUtil {
  19.     // Time conversion constants
  20.     static final long MILLISECS_PER_SECOND  = 1000;
  21.     static final long MILLISECS_PER_MINUTE  = 1000L*60L;
  22.     static final long MILLISECS_PER_HOUR    = 1000L*60L*60L;
  23.     static final long MILLISECS_PER_DAY     = 1000L*60L*60L*24L;
  24.     static final long MILLISECS_PER_WEEK    = 1000L*60L*60L*24L*7L;
  25.     static final long MILLISECS_PER_YEAR    = 1000L*60L*60L*24L*7L*52L;
  26.     static final long DAYS_AGO[] = {
  27.         MILLISECS_PER_DAY,
  28.         MILLISECS_PER_DAY * 6L,
  29.         MILLISECS_PER_DAY * 14L,
  30.         MILLISECS_PER_DAY * 29L,
  31.         MILLISECS_PER_DAY * 59L,
  32.         MILLISECS_PER_DAY * 89L
  33.     };
  34.     static final String TIME_INTERVAL_CP_NAMES[] = { 
  35.         "Minutes", "Hours", "Days", "Weeks", "Years" 
  36.     };
  37.     static final String TIME_INTERVAL_LS_NAMES[] = { 
  38.         "minute", "hour", "day", "week", "year" 
  39.     };
  40.     // Time formaters
  41.     static DateFormat dateFormat = makeGoodFor2000(DateFormat.getDateInstance(DateFormat.SHORT));
  42.     static DateFormat dateTimeFormat = makeGoodFor2000(DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM));
  43.     static DateFormat dateTimeLongFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.MEDIUM);
  44.     static DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
  45.     // for recursion protection of the fatalProgramError method
  46.     static boolean bFatalProgramError = false;  
  47.  
  48.     /*
  49.     This is an all-static class.
  50.     Make the constructor private to no one accidentally tries to instantiate it.
  51.     */
  52.     private WLAUtil() {
  53.             //{{INIT_CONTROLS
  54.         //}}
  55. }
  56.  
  57.     /*
  58.     Called when an unexpected error occurs (due to programming bug, etc).
  59.     Prints a stack trace to stderr, displays an alert, then exits the program.
  60.     */
  61.     public static void fatalProgramError() {
  62.         fatalProgramError(null);
  63.     }
  64.     
  65.     /*
  66.     Called when an unexpected error occurs (due to programming bug, etc).
  67.     Prints a stack trace to stderr, displays an alert, then exits the program.
  68.     If an exception is provided, uses that for its message and stack trace.
  69.     */
  70.     public static void fatalProgramError(Throwable x) {
  71.         // Send error info to std err
  72.         System.err.println("Fatal program error:");
  73.         if(x == null) {
  74.             x = new Throwable();
  75.         } else {
  76.             System.err.println(x.toString());
  77.         }
  78.         x.printStackTrace();
  79.         System.err.flush();
  80.         // Try to display err message before stopping program
  81.         if(!bFatalProgramError && WebLogAnalyzer.theWLA != null) {
  82.             // protect against recursion
  83.             bFatalProgramError = true;
  84.             new AlertDialog(WebLogAnalyzer.theWLA, 
  85.                             false, 
  86.                             "Fatal progam error (software bug!)."
  87.                             );
  88.             bFatalProgramError = false;
  89.         }
  90.         // Exit program
  91.         System.exit(-1);
  92.     }
  93.  
  94.     /*
  95.     Parses date & time text (in local timezone), returning Date.
  96.     Throws a ParseException if a problem occurs.
  97.     */
  98.     static Date string2DateTime(String dateTimeString) throws java.text.ParseException {
  99.         Date d;
  100.         // first assume time is included
  101.         try {
  102.             d = dateTimeFormat.parse(dateTimeString);
  103.             return d;
  104.         } catch(java.text.ParseException x) {
  105.         }
  106.         // try without time
  107.         d = dateFormat.parse(dateTimeString);
  108.         return d;
  109.     }
  110.     
  111.     /*
  112.     Parses date text (in local timezone), returning Date.
  113.     Throws a ParseException if a problem occurs.
  114.     */
  115.     static Date string2Date(String dateString) throws java.text.ParseException {
  116.         return dateFormat.parse(dateString);
  117.     }
  118.     
  119.     /*
  120.     Parses time text (in local timezone), returning Date.
  121.     Throws a ParseException if a problem occurs.
  122.     */
  123.     static Date string2Time(String timeString) throws java.text.ParseException {
  124.         return timeFormat.parse(timeString);
  125.     }
  126.     
  127.     /*
  128.     Converts a Date to a String.
  129.     Returns a date-only string (without time) in the local timezone.
  130.     */
  131.     static String date2String(Date date) {
  132.         return dateFormat.format(date);
  133.     }
  134.  
  135.     /*
  136.     Converts a Date to a String.
  137.     Returns a date & time string in the local timezone.
  138.     */
  139.     static String dateTime2String(Date date) {
  140.         return dateTimeFormat.format(date);
  141.     }
  142.  
  143.     /*
  144.     Converts a date millisecond value (in GMT) to a String.
  145.     Returns a date & time string in the local timezone.
  146.     */
  147.     static String millisecondsTime2String(long ms) {
  148.         return dateTime2String(new Date(ms));
  149.     }
  150.  
  151.     /*
  152.     Converts a Date to a String.
  153.     Returns a verbose date & time string in the local timezone.
  154.     */
  155.     static String dateTime2StringLong(Date date) {
  156.         return dateTimeLongFormat.format(date);
  157.     }
  158.  
  159.     /*
  160.     Converts a time delta in milliseconds to a String.
  161.     Returns an HH:MM:SS formatted string.
  162.     */
  163.     static String timeDelta2String(long millisecs) {
  164.         long hours = millisecs / MILLISECS_PER_HOUR;
  165.         long milliLeft = millisecs - (hours*MILLISECS_PER_HOUR);
  166.         long minutes = milliLeft / MILLISECS_PER_MINUTE;
  167.         milliLeft = milliLeft - (minutes*MILLISECS_PER_MINUTE);
  168.         long seconds = (milliLeft+500) / MILLISECS_PER_SECOND;
  169.         return hours + ":" + minutes + ":" + seconds;
  170.     }
  171.  
  172.     /*
  173.     Converts a H:M:S formatted string into millisecs.
  174.     */
  175.     static long string2TimeDelta(String str) throws java.text.ParseException {
  176.         int idx = 0;
  177.         try {
  178.             int idxEnd = str.indexOf(':');
  179.             long ms = 0;
  180.             ms += MILLISECS_PER_HOUR * Long.parseLong(str.substring(0, idxEnd));
  181.             idx = idxEnd+1;
  182.             idxEnd = str.indexOf(':', idx);
  183.             ms += MILLISECS_PER_MINUTE * Long.parseLong(str.substring(idx, idxEnd));
  184.             idx = idxEnd+1;
  185.             idxEnd = str.length();
  186.             ms += MILLISECS_PER_SECOND * Long.parseLong(str.substring(idx, idxEnd));
  187.             return ms;
  188.         } catch(NumberFormatException x) {
  189.             throw new java.text.ParseException("Invalid time delta numeric format in \"" + str + "\"", idx);
  190.         } catch(ArrayIndexOutOfBoundsException x) {
  191.             throw new java.text.ParseException("Invalid time delta format in \"" + str + "\"", idx);
  192.         }
  193.     }
  194.  
  195.     /*
  196.     Validates the date & time entered in the given TextField.
  197.     If OK, returns true.
  198.     If fails, displays an alert then moves focus to offending TextField.
  199.     */
  200.     static boolean validateDateField(Window dialogOrFrame, TextField dateField) {
  201.         try {
  202.             // Parse the date to ensure OK
  203.             string2Date(dateField.getText());
  204.             // Parsed OK. Passes validation
  205.             return true;
  206.         } catch(java.text.ParseException x) {
  207.             // Can't parse the given date. Move focus to offending field
  208.             dateField.requestFocus();
  209.             dateField.selectAll();
  210.             // Alert user
  211.             new AlertDialog(getFrame(dialogOrFrame), false, x.getMessage());
  212.             return false;
  213.         }
  214.     }
  215.     
  216.     /**
  217.     Centers the given component relative to that component's parent.
  218.     */
  219.     public static void centerInParent(Component comp) {
  220.         Rectangle bounds = comp.getParent().getBounds();
  221.         Rectangle abounds = comp.getBounds();
  222.         comp.setLocation(    bounds.x + (bounds.width - abounds.width)/ 2,
  223.                         bounds.y + (bounds.height - abounds.height)/2
  224.                         );
  225.     }
  226.  
  227.     /*
  228.     Determines the parent Frame of the given Dialog or Frame.
  229.     */
  230.     static Frame getFrame(Window dialogOrFrame) {
  231.         Window w = dialogOrFrame;
  232.         while(w instanceof Dialog) {
  233.             w = (Window)w.getParent();
  234.         }
  235.         return (Frame)w;
  236.     }
  237.  
  238.     /*
  239.     Given a timeframe choice (like: Report.TIMEFRAME_PAST_2_DAYS) returns 
  240.     either the appropriate start or end date as text.
  241.     */
  242.     static String timeframeChoice2DateString(int TIMEFRAME_, boolean wantStartDate) {
  243.         if(TIMEFRAME_ == Report.TIMEFRAME_ALL) {
  244.             return "(all dates)";
  245.         }
  246.         if(TIMEFRAME_ == Report.TIMEFRAME_SPECIFIC) {
  247.             fatalProgramError();    // unexpected
  248.             return null;
  249.         }
  250.         Date date = new Date();
  251.         if(TIMEFRAME_ == Report.TIMEFRAME_TODAY) {
  252.             return date2String(date);
  253.         }
  254.         long millisecs = date.getTime() - MILLISECS_PER_DAY;
  255.         if(TIMEFRAME_ != Report.TIMEFRAME_YESTERDAY && wantStartDate) {
  256.             millisecs -= DAYS_AGO[TIMEFRAME_ - Report.TIMEFRAME_PAST_2_DAYS];
  257.         }
  258.         date.setTime(millisecs);
  259.         return date2String(date);
  260.     }
  261.  
  262.     /*
  263.     Given a time interval in milliseconds (like: WLAUtil.MILLISECS_PER_HOUR),
  264.     returns an index value:
  265.     0="Minutes", 1="Hours", 2="Days", 3="Weeks", 4="Years".
  266.     */
  267.     static int timeInterval2Index(long timeInterval) {
  268.         switch((int)timeInterval) {
  269.             case (int)WLAUtil.MILLISECS_PER_MINUTE:
  270.                 return 0;
  271.             case (int)WLAUtil.MILLISECS_PER_HOUR:
  272.                 return 1;
  273.             case (int)WLAUtil.MILLISECS_PER_DAY:
  274.                 return 2;
  275.             case (int)WLAUtil.MILLISECS_PER_WEEK:
  276.                 return 3;
  277.             case (int)WLAUtil.MILLISECS_PER_YEAR:
  278.                 return 4;
  279.             default:
  280.                 WLAUtil.fatalProgramError();
  281.                 return 0;
  282.         }
  283.     }
  284.     
  285.     /*
  286.     Given a time interval in milliseconds (like: WLAUtil.MILLISECS_PER_HOUR),
  287.     returns an appropriate plural word starting with a capitalized letter:
  288.     "Minutes", "Hours", "Days", "Weeks", "Years".
  289.     */
  290.     static String timeInterval2CapPluralString(long timeInterval) {
  291.         return TIME_INTERVAL_CP_NAMES[timeInterval2Index(timeInterval)];
  292.     }
  293.     
  294.     /*
  295.     Given a time interval in milliseconds (like: WLAUtil.MILLISECS_PER_HOUR),
  296.     returns an appropriate singular word starting with a non-capitalized letter:
  297.     "minute", "hour", "day", "week", "year"
  298.     */
  299.     static String timeInterval2LowerSingularString(long timeInterval) {
  300.         return TIME_INTERVAL_LS_NAMES[timeInterval2Index(timeInterval)];
  301.     }
  302.  
  303.     /*
  304.     Given a string as entered by a user, automatically clean it up into the
  305.     desired URL string. 
  306.     Sample actions:
  307.     "mylog.log"         -> "http://mylog.log/"
  308.     "http://mylog.log"  -> "http://mylog.log/"
  309.     "\mylog.log"        -> "file:///\mylog.log"
  310.     "c:\mylog.log"      -> "file:///c:\mylog.log"
  311.     */
  312.     static String cleanupURLName(String messyURLText) {
  313.         // Infer starting "file://", etc as needed
  314.         try {
  315.             char ch;
  316.             StringBuffer buf;
  317.             // Colon?
  318.             int idx = messyURLText.indexOf(':');
  319.             if(idx < 0) {
  320.                 // No colon.
  321.                 buf = new StringBuffer(messyURLText.length() + 9);
  322.                 ch = messyURLText.charAt(0);
  323.                 if(ch == java.io.File.separatorChar) {
  324.                     // Presume file entry
  325.                     buf.append("file:///");
  326.                     buf.append(messyURLText);
  327.                 } else {
  328.                     //Prepend http:// by default
  329.                     buf.append("http://");
  330.                     buf.append(messyURLText);
  331.                     // if no slashes in messyURL, presume only domain given and end with one
  332.                     if(-1 == messyURLText.indexOf('/')) {
  333.                         buf.append('/');
  334.                     }
  335.                 }
  336.                 return buf.toString();
  337.             }
  338.             // Have a colon in the messyURLText, look at char after the colon
  339.             ch = messyURLText.charAt(++idx);
  340.             if(ch == '/') {
  341.                 ch = messyURLText.charAt(++idx);
  342.                 if(ch == '/') {
  343.                     idx = messyURLText.indexOf(':', ++idx);
  344.                     if(idx < 0) {
  345.                         // only initial "//" provided. Add ending one.
  346.                         buf = new StringBuffer(messyURLText.length() + 2);
  347.                         buf.append(messyURLText);
  348.                         buf.append('/');
  349.                         return buf.toString();
  350.                     }
  351.                 }
  352.                 // protocol specified. Nothing to do.
  353.                 return messyURLText;
  354.             }
  355.             if(ch == '\\') {
  356.                 // MSDOS file path. Prefix file: protocol
  357.                 return "file:///" + messyURLText;
  358.             }
  359.             //colon, but no slash...do nothing
  360.         } catch(StringIndexOutOfBoundsException x) {
  361.             // if get this, no cleanup
  362.         }
  363.         return messyURLText;
  364.     }
  365.  
  366.     /*
  367.     Allows the user to browse locally for a log file.
  368.     Shows the standard open dialog, then, if the user chooses a file,
  369.     it "cleans up" the filename into a URL using the cleanupURLName() 
  370.     method.
  371.     Template is the inititial filename in the open dialog.
  372.     If the user cancels the dialog, null is returned.
  373.     */
  374.     public static String browseForURL(String template) {
  375.         // Access main frame which has the open dialog off it
  376.         WebLogAnalyzer wla = WebLogAnalyzer.theWLA;
  377.         
  378.         // set the default suffix
  379.         wla.openFileURLDialog.setFile(template);
  380.  
  381.         // Show the OpenFileDialog
  382.         wla.openFileURLDialog.show();
  383.         
  384.         // get the results
  385.         String results = wla.openFileURLDialog.getFile();
  386.         if(results != null) {
  387.             results = wla.openFileURLDialog.getDirectory() + results;
  388.               results = WLAUtil.cleanupURLName(results);
  389.         }
  390.         return results;
  391.     }
  392.  
  393. /*
  394. This sort routine was modified from Sun's SortDemo, and thus the long copyright, etc.
  395. The original sorted an array of integers.
  396. The modified version sorts an array of Objects the implement the Sortable interface.
  397. */
  398.  
  399. /*
  400.  * @(#)QSortAlgorithm.java    1.6 96/12/06
  401.  *
  402.  * Copyright (c) 1994-1996 Sun Microsystems, Inc. All Rights Reserved.
  403.  *
  404.  * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
  405.  * modify and redistribute this software in source and binary code form,
  406.  * provided that i) this copyright notice and license appear on all copies of
  407.  * the software; and ii) Licensee does not utilize the software in a manner
  408.  * which is disparaging to Sun.
  409.  *
  410.  * This software is provided "AS IS," without a warranty of any kind. ALL
  411.  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
  412.  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
  413.  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
  414.  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
  415.  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
  416.  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
  417.  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
  418.  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
  419.  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
  420.  * POSSIBILITY OF SUCH DAMAGES.
  421.  *
  422.  * This software is not designed or intended for use in on-line control of
  423.  * aircraft, air traffic, aircraft navigation or aircraft communications; or in
  424.  * the design, construction, operation or maintenance of any nuclear
  425.  * facility. Licensee represents and warrants that it will not use or
  426.  * redistribute the Software for such purposes.
  427.  */
  428.  
  429.    public static void quickSort(Sortable a[])
  430.    {
  431.       doQuickSort(a, 0, a.length - 1);
  432.    }
  433.     
  434.    /** This is a generic version of C.A.R Hoare's Quick Sort 
  435.     * algorithm.  This will handle arrays that are already
  436.     * sorted, and arrays with duplicate keys.<BR>
  437.     *
  438.     * If you think of a one dimensional array as going from
  439.     * the lowest index on the left to the highest index on the right
  440.     * then the parameters to this function are lowest index or
  441.     * left and highest index or right.  The first time you call
  442.     * this function it will be with the parameters 0, a.length - 1.
  443.     *
  444.     * @param a       an Sortable array
  445.     * @param lo0     left boundary of array partition
  446.     * @param hi0     right boundary of array partition
  447.     */
  448.    private static void doQuickSort(Sortable a[], int lo0, int hi0)
  449.    {
  450.       int lo = lo0;
  451.       int hi = hi0;
  452.       Sortable midObj;
  453.  
  454.       if ( hi0 > lo0)
  455.       {
  456.  
  457.          /* Arbitrarily establishing partition element as the midpoint of
  458.           * the array.
  459.           */
  460.          midObj = a[ ( lo0 + hi0 ) / 2 ];
  461.  
  462.          // loop through the array until indices cross
  463.          while( lo <= hi )
  464.          {
  465.             /* find the first element that is greater than or equal to 
  466.              * the partition element starting from the left Index.
  467.              */
  468.          while( ( lo < hi0 ) && midObj.isLessThan(a[lo]))
  469.          ++lo;
  470.  
  471.             /* find an element that is smaller than or equal to 
  472.              * the partition element starting from the right Index.
  473.              */
  474.          while( ( hi > lo0 ) && !midObj.isLessThanOrEqual(a[hi]))
  475.          --hi;
  476.  
  477.             // if the indexes have not crossed, swap
  478.             if( lo <= hi ) 
  479.             {
  480.                // swap
  481.                Sortable T;
  482.                T = a[lo]; 
  483.                a[lo] = a[hi];
  484.                a[hi] = T;
  485.                //
  486.                ++lo;
  487.                --hi;
  488.             }
  489.          }
  490.  
  491.          /* If the right index has not reached the left side of array
  492.           * must now sort the left partition.
  493.           */
  494.          if( lo0 < hi )
  495.             doQuickSort( a, lo0, hi );
  496.  
  497.          /* If the left index has not reached the right side of array
  498.           * must now sort the right partition.
  499.           */
  500.          if( lo < hi0 )
  501.             doQuickSort( a, lo, hi0 );
  502.  
  503.       }
  504.    }
  505.  
  506.     /*
  507.     Ensures the given DateFormat has 4 year digits so that it may
  508.     handle the year 2000.
  509.     */
  510.     private static DateFormat makeGoodFor2000(DateFormat dateFormat) {
  511.         SimpleDateFormat sdf;
  512.         try {
  513.             sdf = (SimpleDateFormat)dateFormat;
  514.         } catch(ClassCastException x) {
  515.             // can't handle this uncommon dateFormat
  516.             return dateFormat;
  517.         }
  518.         // ensure year displayed as 4 digits
  519.         String pattern = sdf.toLocalizedPattern();
  520.         int i = pattern.indexOf("yyyy");
  521.         if(i != -1) {
  522.             // pattern is already as a 4 digit year
  523.             return dateFormat;
  524.         }
  525.         // modify the pattern so that it has a 4 digit year
  526.         i = pattern.indexOf("yy");
  527.         if(i != -1) {
  528.             pattern = pattern.substring(0,i) + "yyyy" + pattern.substring(i+2, pattern.length());
  529.             sdf = new SimpleDateFormat(pattern);
  530.         }
  531.         return sdf;
  532.     }
  533.     //{{DECLARE_CONTROLS
  534.     //}}
  535. }
  536.  
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543.     
  544.  
  545.