Creating a Portable Bookmark Library using Java
Complete Program Listing
/* File Bookmarks02a.java Copyright 2005, R.G.Baldwin Revised 08/31/05 This program is the same as Bookmarks02, except that the following two methods have been replaced by stub methods for test purposes. getFireFoxBookmarks getIEBookmarks The purpose of this program is to: 1-Extract bookmarks from one or more FireFox, Netscape, or Internet Explorer (IE) browsers within a specified range of bookmark indices. 2-Construct an Email message containing the name and the URL of each extracted bookmark. 3-Send the message to a specified destination Email address. (Note that the actual sending of the messages may have been disabled for test purposes. Search for the word disable to find the code that may have been disabled.) Each Email message is formatted with the name of the bookmark as the subject and the URL for the bookmark in the body of the message. To use this message as a bookmark later, simply open the message and double-click on the URL. The subject may optionally be prepended with a text string provided by the user as bkMrkCode below. The string that is prepended to the subject can be used by the Email client to recognize the message as a bookmark message. If you don't want an actual string prepended to the subject, specify this parameter as an empty string, "". The program also maintains a historical list of bookmarks that have previously been sent to the destination Email address. The historical list is maintained in a text file that can easily be edited by the user if such editing becomes necessary. Several backup copies of the file are automatically generated and maintained. The historical file is named BkMrkHistory.txt. If it doesn't already exist, it is automatically created in a folder specified by the user and identified below as dataOutPath. Once the file exists, it is backed up at the beginning of each successive run of the program. Then it is updated during that run. Bookmarks in the historical list are not sent to the destination Email address. This prevents the sending of duplicate bookmark messages during successive runs of the program. Once all the bookmarks in the FireFox or Netscape bookmark file (or the IE Favorites folder) have been sent to the destination Email address, this program will send only those bookmarks that have been added or changed since the last time the program was run. Because the number of messages that could be sent the first time the program is run could overwhelm the SMTP server, the program allows the user to specify the index of the first bookmark to be sent and the maximum number of bookmarks to be sent during any particular run. For example, if values of 0 and 100 are used the first time the program is run, it can be expected that 100 messages will be sent (assuming that there are at least 100 bookmarks). These are the messages required to send bookmarks with indices of 0 through 99. If values of 0 and 200 are used the second time the program is run, it can be expected that 100 or more messages will be sent (assuming that there are at least 200 bookmarks). This will consist of any new bookmarks in the index range of 0 through 99 plus all of the bookmarks in the index range of 100 through 199. The following values must be provided as command-line parameters. All command-line parameters are provided as strings, but must be convertible to the types shown below. String destAdr: Email address to which bookmarks are to be sent. String smtpServer: An SMTP server that can be used to send the messages. String bkMrkPath: Path to the folder containing the FireFox bookmark file, or containing the IE Favorites files. String bkMrkFile: Name of the FireFox or Netscape bookmark file. Provide a dummy name if you are processing IE favorites. String dataOutPath: Path to a folder where output files will be stored. Make sure that this folder is on the path for your regular backups, because you don't want to lose these files in case of a disk failure. String bkMrkCode: Unique code that is prepended to the Subject of the Email message to identify the message as a bookmark message. int lowBkMrkLimit: First bookmark index to process. int numToProc: Number of bookmarks to process. String browser: Type of browser: F for FireFox, N for Navigator, or I for Internet Explorer. boolean sendMsgs: Specify true or false. Messages will be sent on true. Message will not be sent, but statistics will be displayed on false. Tested using J2SE 5.0 under WinXP. J2SE 5.0 or later is required due to the use of generics. **********************************************************/ import java.io.*; import java.nio.channels.*; import java.util.*; import sun.net.smtp.SmtpClient; import java.awt.*; class Bookmarks02a{ public static void main(String[] args){ //Confirm correct number of command-line parameters. // If the number is not correct, display a usage msg // and terminate the program. if(args.length != 10){ System.out.println("Command-line parameter error"); System.out.println(); System.out.println("Usage: java Bookmarks02a"); System.out.println("followed by:"); System.out.println("Destination Email address"); System.out.println("SMTP Server"); System.out.println("Bookmark path"); System.out.println("Bookmark file"); System.out.println("Output data path"); System.out.println("Bookmark code"); System.out.println("Low bookmark limit"); System.out.println("Number bookmarks to process"); System.out.println("Browser, F, N, or I"); System.out.println("Permission to send messages"); System.out.println(); System.out.println("Terminating Program"); System.exit(0); }//end if //The following values are provided as command-line // parameters. //Email address to which bookmarks are to be sent. String destAdr = args[0]; //An SMTP server that can be used to send the messages. String smtpServer = args[1]; //Path to the folder containing a FireFox bookmark // file or containing a multitude of IE .url files. String bkMrkPath = args[2]; //Name of the FireFox bookmark file. Just use a // dummy name for this parameter when processing IE // favorites String bkMrkFile = args[3]; //Path to the folder where output files will be stored. String dataOutPath = args[4]; //Unique code that identifies a bookmark msg to // destAdr. This code is prepended onto the name of // the bookmark and the name is put in the Subject line // of the message. String bkMrkCode = args[5]; //Index of first bookmark to process. int lowBkMrkLimit = Integer.parseInt(args[6]); //Number of bookmarks to process. int numToProc = Integer.parseInt(args[7]); //Type of browser: F for FireFox, N for Navigator, // or I for Internet Explorer. String browser = args[8]; //Send msgs on true. Just display statistics on false. boolean sendMsgs = false;//default value //End of command-line parameters //Convert the last parameter from String to boolean // and overwrite default if appropriate. if(args[9].toUpperCase().equals("TRUE")){ sendMsgs = true; }//end if //Instantiate a new object of this class. Bookmarks02a thisObj = new Bookmarks02a(); //Create a new bookmark history file if it doesn't // already exist. If it does exist, just leave it // alone. String bkMrkHistFile = dataOutPath + "BkMrkHistory.txt"; thisObj.createHistFile(bkMrkHistFile); //Create a TreeSet object to contain the bookmarks from // the bookmark history file. //This collection is used to store the contents // of the history file for processing. It gets updated // when bookmarks are sent to the destAdr and the final // contents are written out into a new history file. TreeSet <String>bkMrkHistList = thisObj.makeBkMrkHistList(bkMrkHistFile); //Get the name and the URL for each of the bookmarks. // Encapsulate them in an object of type Bookmark. // Encapsulate all of the Bookmark objects in an object // of type ArrayList. //When processing bookmarks from a FireFox or Navigator // browser, make a copy of the bookmark file. Process // the copy instead of the original in order to reduce // the likelihood of inadvertently corrupting the // original bookmark file. //The following collection encapsulates all of the // bookmarks awaiting final processing. The // getIEBookmarks method requires that a method // parameter points to the ArrayList object on input // because of its recursive nature. The // getFireFoxBookmarks method is not recursive and it // overwrites this object with a new ArrayList object // that it creates. ArrayList <Bookmark> theBookmarks = new ArrayList <Bookmark>(); String tempBkMrkFile = "BkMrkTemp.html"; if(browser.toUpperCase().equals("F")){ //Process FireFox bookmarks. thisObj.copyBkMrkFile(bkMrkPath,bkMrkFile, dataOutPath,tempBkMrkFile); theBookmarks = thisObj.getFireFoxBookmarks( dataOutPath,tempBkMrkFile); }else if(browser.toUpperCase().equals("N")){ //Process Netscape Navigator bookmarks. Same format // as FireFox thisObj.copyBkMrkFile(bkMrkPath,bkMrkFile, dataOutPath,tempBkMrkFile); theBookmarks = thisObj.getFireFoxBookmarks( dataOutPath,tempBkMrkFile); }else if(browser.toUpperCase().equals("I")){ //Process Inernet Explorer favorites. theBookmarks = thisObj.getIEBookmarks( bkMrkPath,theBookmarks); }else{ System.out.println("Don't recognize browser"); System.out.println("Terminating program"); System.exit(0); }//end else //Process the ArrayList object, either extracting and // sending bookmarks as messages to destAdr, or simply // extracting and displaying the statistics. The // TreeSet object will be updated to contain an // identification of all bookmarks sent to destAdr. thisObj.processBkMrks(destAdr, smtpServer, bkMrkCode, lowBkMrkLimit, numToProc, sendMsgs, bkMrkHistList, theBookmarks); //Write a new bookmark history file containing the // final contents of the TreeSet object. thisObj.writeBkMrkHistFile( bkMrkHistFile,bkMrkHistList); }// end main //-----------------------------------------------------// //This method creates a new history file if it doesn't // already exist. void createHistFile(String bkMrkHistFile){ try{ new File(bkMrkHistFile).createNewFile(); }catch(Exception e){ e.printStackTrace(); }//end catch }//end createHostFile //-----------------------------------------------------// //This method processes bookmarks previously stored in an // ArrayList object. //If the value of sendMsgs is true, the method constructs // an Email message for each bookmark and sends it to // destAdr. Otherwise the method simply displays // statistics regarding the number of messages that would // be sent if the value of sendMsgs were true. void processBkMrks(String destAdr, String smtpServer, String bkMrkCode, int lowBkMrkLimit, int numToProc, boolean sendMsgs, TreeSet <String>bkMrkHistList, ArrayList <Bookmark> theBookmarks){ //Process the name and the URL for the bookmark. The // bookmark is ignored unless it is within the range of // bookmarks specified for processing and it is not // contained in the bookmark history file. If it is in // the bookmark history file, that means that it was // previously sent to the destination address. In this // case, it is ignored to avoid creating duplicate // bookmark at destAdr. //The following counter counts the number of bookmarks // that are eligible for sending to destAdr according // to the criteria given above. int msgCounter = 0; String theName = null; String theUrl = null; for(int cnt = 0;cnt < theBookmarks.size();cnt++){ theName = theBookmarks.get(cnt).bkMrkName; theUrl = theBookmarks.get(cnt).bkMrkUrl; if((cnt >= lowBkMrkLimit) && (cnt < lowBkMrkLimit + numToProc) && (!bkMrkHistList.contains(theName + theUrl))){ //This bookmark is eligible for sending to destAdr. msgCounter++; //Display the names of the eligible bookmark // on the command-line screen. System.out.println(cnt + " " + theName); //Decide whether to send the bookmark to destAdr, // or to simply display the statistics on eligible // bookmarks. if(sendMsgs){ //sendMsgs is true //Construct the message. Put the name of the // bookmark in the Subject line, prepended // by bkMrkCode + ":". Put three dots and the // URL on the first line of the body of the // message. Leave the third line blank. Put a // unique code on the fourth line to make the // message identifiable by a search regardless of // the bookmark name and URL. String message ="Subject: " + bkMrkCode + ":" + theName + "nn" + " ... " + theUrl + "nn" + "aiNy4DpjnVCgP190KrbCoP"; try{ //Call the method to actually send the // message. The method will return false // if it is unable to send the message. boolean success = true; //Disable the following statement to avoid // sending messages during testing. success = sendBkMrk( destAdr,smtpServer,message); if(!success){ //If unable to send the message. This will // terminate the program and print the // error message shown. throw new Exception( "Unable to send: " + theName); }//end if //Update the history list to contain the // bookmark that was just sent to the // destAdr. Concatenate the name and the // URL of the bookmark and put that string // in the history list. bkMrkHistList.add(theName + theUrl); }catch(Exception ex){ ex.printStackTrace(); System.exit(0); }//end catch }//end if }//end if }//end for loop //Display summary information about the run. System.out.println( "Number eligible bookmarks = " + msgCounter); if(sendMsgs){ //sendMgs is true. //All eligigle bookmarks will have been sent. System.out.println("Bookmarks sent = " + msgCounter); }else{ //sendMsgs is false. System.out.println("Bookmarks sent = " + 0); }//end else System.out.println( "Bookmark range = " + lowBkMrkLimit + " to " + (lowBkMrkLimit + numToProc)); System.out.println( "Total number bookmarks = " + theBookmarks.size()); }//end processBkMrks //-----------------------------------------------------// //The purpose of this method is to send the message // to the destAdr. boolean sendBkMrk(String destAdr, String smtpServer, String message){ try{ //Pass a string containing the name of the smtp // server as a parameter to the following // constructor. SmtpClient smtp = new SmtpClient(smtpServer); //Pass any valid Email address to the from() method. smtp.from(destAdr); //Pass the Email address of the destAdr to the // to() method. smtp.to(destAdr); //Get an output stream for the message PrintStream msg = smtp.startMessage(); //Write the message into the output stream. msg.println(message); //Close the stream, sending the message smtp.closeServer(); return true;//on successful send }catch( Exception e ){ e.printStackTrace(); System.out.println("while sending Email"); //Sound an alarm. try{ Thread.currentThread().sleep(500); Toolkit.getDefaultToolkit().beep(); Thread.currentThread().sleep(500); Toolkit.getDefaultToolkit().beep(); Thread.currentThread().sleep(500); Toolkit.getDefaultToolkit().beep(); Thread.currentThread().sleep(500); }catch(Exception ex){ ex.printStackTrace(); }//end catch //Return false to indicate that the msg // was not successfully forwarded. return false; }//end catch }//end sendBkMrk //-----------------------------------------------------// //This method reads a text file and causes each line of // text in the file to become an element in a TreeSet // object. A TreeSet object contains no duplicates. //After creating the TreeSet object, the method writes // the data from the TreeSet into a backup file named // ....bakN, where the value of N is explained below. //A new backup file with a unique name based on N is // created each time the method is executed. Once the // number of backup files reaches 5, the method // automatically deletes the oldest file before creating // a new backup file. Thus the method automatically // maintains a sequence of five backup files with // extensions .bak0 through bak5 with one number missing. // The age-order of the files should be determined by // the modification date and not by the name of the file. TreeSet <String> makeBkMrkHistList(String bkMrkHistFile){ TreeSet <String> bkMrkHistList = new TreeSet<String>(); //Read lines of text from text file and populate the // TreeSet object. try{ BufferedReader inData = new BufferedReader( new FileReader(bkMrkHistFile)); String data; //temp holding area while((data = inData.readLine()) != null){ bkMrkHistList.add(data); }//end while loop inData.close();//Close input file //Write a backup file before terminating the method. //First determine the name of the next backup file // allowed in the directory. int N = 0; File theFile = null; String baseFileName = bkMrkHistFile. substring(0,bkMrkHistFile.indexOf(".txt")); for(N = 0;N < 6;N++){ theFile = new File(baseFileName + ".bak" + N); if(!(theFile.exists()))break; }//end for loop //Cause N to rotate from 0 through 5 if(N == 5){//del file 0 for use next time new File(baseFileName + ".bak0").delete(); }//end if else{//delete the next file in sequence if(new File(baseFileName + ".bak" + (N + 1)).exists()){ new File( baseFileName + ".bak"+ (N + 1)).delete(); }//end if }//end else //Now write the output file DataOutputStream dataOut = new DataOutputStream( new FileOutputStream(theFile)); //Use an Iterator object to access the data // in the TreeSet object. Iterator <String>iter = bkMrkHistList.iterator(); while(iter.hasNext()){ data = iter.next(); dataOut.writeBytes(data + "n"); }//end while dataOut.close(); }catch(Exception e){ e.printStackTrace(); }//end catch return bkMrkHistList; }//end makeBkMrkHistList //-----------------------------------------------------// //This method writes the data from a TreeSet object into // an output file. void writeBkMrkHistFile(String bkMrkHistFile, TreeSet <String>bkMrkHistList){ try{ DataOutputStream dataOut = new DataOutputStream( new FileOutputStream(bkMrkHistFile)); //Use an iterator to access the data in // the TreeSet object. Iterator <String>iter = bkMrkHistList.iterator(); String data; while(iter.hasNext()){ data = iter.next(); dataOut.writeBytes(data + "n"); }//end while dataOut.close(); }catch(Exception e){e.printStackTrace();} }//end writeBkMrkHistFile //-----------------------------------------------------// //This method copies the "official" book mark file into a // temporary book mark file to avoid any possibility of // corrupting the official book mark file during // processing. void copyBkMrkFile(String bkMrkPath, String bkMrkFile, String dataOutPath, String tempBkMrkFile){ try{ FileChannel inputChannel = new FileInputStream( bkMrkPath + bkMrkFile).getChannel(); FileChannel outputChannel = new FileOutputStream( dataOutPath + tempBkMrkFile).getChannel(); // Copy file contents from input file to output file outputChannel.transferFrom( inputChannel, 0, inputChannel.size()); inputChannel.close(); outputChannel.close(); }catch (IOException e){ e.printStackTrace(); }//end catch }//end copyFile //-----------------------------------------------------// //This is a stub method that creates and returns two // dummy bookmarks. This method is used to test the // rest of the program. ArrayList <Bookmark> getFireFoxBookmarks( String dataOutPath,String tempBkMrkFile){ ArrayList <Bookmark> theBookmarks = new ArrayList <Bookmark>(); theBookmarks.add(new Bookmark( "Dummy Firefox bookmark 1","theUrl")); theBookmarks.add(new Bookmark( "Dummy Firefox bookmark 2","theUrl")); return theBookmarks; }//end getFireFoxBookmarks //-----------------------------------------------------// //This is a stub method that creates and returns two // dummy bookmarks. This method is used to test the // rest of the program. ArrayList <Bookmark> getIEBookmarks( String bkMrkPath,ArrayList <Bookmark> theBookmarks){ theBookmarks.add(new Bookmark( "Dummy IE bookmark 1","theUrl")); theBookmarks.add(new Bookmark( "Dummy IE bookmark 2","theUrl")); return theBookmarks; }//end getIEBookmarks //-----------------------------------------------------// //This is a helper method called by getIEBookmarks. The // purpose of this method is to extract the URL from a // Microsoft .url file. String getTheUrl(String pathAndFile){ try{ BufferedReader inData = new BufferedReader( new FileReader(pathAndFile)); String data; //temp holding area while((data = inData.readLine()) != null){ if(data.startsWith("URL=")){ String theUrl = data.substring(4); inData.close();//Close input file return theUrl; }//end if }//end while loop inData.close();//Close input file }catch(Exception e){ e.printStackTrace(); }//end catch System.out.println("No URL Found"); return "No URL Found"; }//end getTheUrl //-----------------------------------------------------// //This is an inner class, the purpose of which is to // encapsulate the name and the URL for a bookmark. class Bookmark{ String bkMrkName; String bkMrkUrl; Bookmark(String bkMrkName,String bkMrkUrl){ this.bkMrkName = bkMrkName; this.bkMrkUrl = bkMrkUrl; }//end constructor }//end inner class Bookmark //-----------------------------------------------------// }//end class Bookmarks02a definition |
Copyright 2005, Richard G. Baldwin. Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.
About the author
Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.
In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP). His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments. (TI is still a world leader in DSP.) In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.
Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.
Page 3 of 3