Working with Users - HISTORY.HTM
You really need to tell the users why they just down loaded a new version of the program when you make an update. The way I do this follows:
1. I update a file called HISTORY.HTM each time I update the program. This file is included as part of the main jar.
2. I have a user row in a database table (or a user preference) that contains the date of the last HISTORY.HTM file the user viewed.
3. As part of start up, I collect the stored date and compare it with the file date on the HISTORY.HTM file included in the downloaded jar.
4. If the jar version is newer, the user is offered an option to view the new HISTORY.HTM file.
5. A menu option in the program allows the user to view the HISTORY.HTM file at any time.
Code to check the HISTORY.HTM file date inside the jar and view the HTML file follows: (Note: this code shows how to access a text file that is located inside a jar file.)
/*
* History.java
*
* Created on September 12, 2002, 3:13 PM
*
*/
package src.DeliverPrc;
import java.net.*;
import java.io.*;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.event.*;
import java.net.URLConnection;
import javax.swing.JScrollPane;
import java.util.*;
/*
* Description - History - Show the user History.html if it is more recent that the last they saw
* Each new version of JavaDeliver comes with an updated version of History.html. This class looks
* up the date of the last History.html the user has viewed (in the USER table) and if the one in
* the jar file is newer, it offers them the option of viewing the file.
* Part of the DayBegin routine that carries out several tasks like this.
* When called from the main menu the view is forced to be true.
* The class checks first for a history.html file in the current folder (for development and
* testing. If it doesn't find that, it looks in the jar file the program is running from
* @author - Hale Pringle
* @version - 1.0
*
*
* Took some of the code for reading files from inside archives from
* javaworld "Modify archives, Part 1"
* Allen Holub
*
* The StreamEditorPane code came from Core JFC by Kim Topley
*
* Needs a print button
*/
public class History {
private JFrame f;
private Model mod;
private Model.UserTableModel utm;
/**
*
* Description - main method for testing History class
*
* @param - none used
* @return - nothing
*/
public static void main(String[] args)
{ java.util.Date oldDate = new Date();
Model mod;
DBMaster dbc;
mod = new Model();
dbc = new src.DeliverPrc.DBMaster(mod);
new History(mod, oldDate, true);
}
/**
*
* Description - Constructor for the History class
*
* @param - model, Model class passed to almost all the routines
* @param - Date - the date the user last viewed the history.html file
* @param - boolean - isForceView - should the user be asked if they want to see the history.html
* file (false) or should they be shown the file immediately (true)
* @return - nothing
* @exception - none
*
*/
public History(Model model,java.util.Date inDate, boolean isForceView) {
mod = model;
long chkDate = inDate.getTime();
GregorianCalendar checkDate = new GregorianCalendar();
checkDate.setTimeInMillis(chkDate);
utm = model.getUserTableModel();
try {
URL imgPath1;
String imgPath2, imgPath3,iniPath;
imgPath1 = History.class.getProtectionDomain().getCodeSource().getLocation();
imgPath2 = imgPath1.toString();
//imgPath2 = imgPath2.substring(6);
imgPath3 = imgPath2+"History.htm";
// if (imgPath2.indexOf(".jar")> 0){
String imgPath4 = imgPath2.substring(0,imgPath2.lastIndexOf("/"));
String path_to_file = "History.htm";
String imgPath5 = imgPath4.substring(imgPath4.indexOf("/")+1);
File inPath = new File(imgPath5+"\\History.htm");
URL file_url;
URL cache_url;
BufferedReader reader ;
long lDay;
boolean isInJar;
// If the text file HISTORY.HTM in the current folder exists
if (inPath.exists()){
cache_url = new URL(imgPath4+"/");
file_url = new URL( cache_url, path_to_file );
URLConnection connection =
(URLConnection)( file_url.openConnection() );
lDay = connection.getLastModified();
reader = new BufferedReader(new FileReader(inPath));
isInJar = false;
} else { // look in the jar file
File inJar = new File(imgPath4+"/RMDeliver.jar");
isInJar = true;
cache_url = new URL("jar:"+ imgPath4+"/RMDeliver.jar!/");
// NOTE: the bang (!) at the end of the previous line
file_url = new URL( cache_url, path_to_file );
JarURLConnection connection =
(JarURLConnection)( file_url.openConnection() );
//System.out.println("modified since" +connection.getIfModifiedSince());
lDay = connection.getLastModified();
connection.setDoInput(true);
connection.setDoOutput(false);
connection.connect();
InputStream is = connection.getInputStream();
reader = new BufferedReader( new InputStreamReader(is) );
}
//java.util.Date historyFileDate = new java.util.Date(lDay);
GregorianCalendar historyFileDate = new GregorianCalendar();
historyFileDate.setTimeInMillis(lDay);
if (!isForceView) {
if ( (historyFileDate.get(Calendar.DAY_OF_MONTH) == checkDate.get(Calendar.DAY_OF_MONTH)
&& historyFileDate.get(Calendar.MONTH) == checkDate.get(Calendar.MONTH)
&& historyFileDate.get(Calendar.YEAR) == checkDate.get(Calendar.YEAR))){
//do nothing, they have seen this history file
return;
} else {
//
Object[] options = {"Yes", "No!"};
int n = JOptionPane.showOptionDialog(f,
"There is a new version of the Program. View the Change log?"+
"\n (Note: it will take a few seconds to load)",
"History Log",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
if (n == JOptionPane.NO_OPTION) {
return;
}// else if (n == JOptionPane.YES_OPTION) { }
//
}
} // end isForceView
// update the date in Usert file to match the date of the file just read.
java.util.Date outDate = historyFileDate.getTime();
// System.out.println("check date out of history: "+outDate.toString());
String values = "historydt = '"+outDate.toString()+"'";
String userName = mod.getCurrentUser();
utm.UpdateTable(values,userName);
utm.fire();
String sText="";
String aline;
boolean addBreak = false;
while ((aline = reader.readLine()) != null ){ //&& aline.length() > 0){
if (aline.trim().equalsIgnoreCase("</HEAD>")){addBreak = true;}
sText = sText + aline ;
if (addBreak) {
//sText = sText + "<br>";
}
}
try {
f = new JFrame("History File");
mod.doIcon(f,"pickup-empty.gif");
StreamEditorPane ep = new StreamEditorPane();
JScrollPane js = new JScrollPane(ep);
f.getContentPane().add(js);
f.setSize(600, 400);
java.awt.Point lastLocation = null;
lastLocation = f.getLocation();
if (lastLocation != null) {
//Move the window over and down 40 pixels.
lastLocation.translate(40, 100);
}
f.setLocation(lastLocation);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
f.setVisible(false);
f.dispose();
}
});
ep.setTextInput(sText);
f.setVisible(true);
} catch (FileNotFoundException e) {
System.out.println("Failed to open file "+path_to_file); // + args[0]);
//System.exit(1);
f.setVisible(false);
f.dispose();
} catch (IOException e) {
System.out.println("Error while reading file " +path_to_file); //+ args[0]);
// System.exit(1);
f.setVisible(false);
f.dispose();
} catch (Throwable t) {
System.out.println("Unexpected exception: " + t);
//System.exit(1);
f.setVisible(false);
f.dispose();
}
}
catch( MalformedURLException e ){ System.out.println(e); }
catch( IOException e ) { System.out.println(e); }
}
/**
*
* Description - path_for takes a package name (e.g. com.john) and returns a path (eg./com/john)
*
* @param class name in dot format
* @return path name with slashes instead of dots
*
*/
private String path_for(String class_name) {
String path_name = class_name.replace('.', '/');
return "/" + path_name ;
}
}
=========================
package src.DeliverPrc;
/**
* Description StreamEditorPane.java - Editor pane to display HTML text
*
* Created on September 13, 2002, 9:16 AM
* Modified from JFC Swing Book example
*
* @author Hale Pringle
* @version version 1.0
*/
import javax.swing.*;
import javax.swing.text.*;
import java.awt.event.*;
import java.io.*;
import java.net.URLConnection;
/*
* Description -Constructor for StreamEditorPane.java
*
*/
public class StreamEditorPane extends JEditorPane {
/*
* Description -setInput Stream - get input to display
* @param - InputStream - a stream set up by the calling object
*/
public void setInputStream(InputStream is) throws IOException,
BadLocationException {
String type = guessContentType(is);
if (type == null) {
// Unknown type - use plain text
type = "text/plain";
}
System.out.println("File content type is " + type);
// Set the new content type
setContentType(type);
// Now create the appropriate document and install it
Document doc = getEditorKit().createDefaultDocument();
setDocument(doc);
// Finally, read the date from the stream
getEditorKit().read(is, doc, 0);
}
/*
* Description -setReader - set the data reader - this is setup and called by calling object
* @param - BufferedReader - set up by calling object and passed in
*/
public void setReader(BufferedReader reader) throws IOException,
BadLocationException {
String type; // = guessContentType(is);
//if (type == null) {
// Unknown type - use plain text
type = "text/html";
//}
//System.out.println("File content type is " + type);
// Set the new content type
setContentType(type);
// Now create the appropriate document and install it
Document doc = getEditorKit().createDefaultDocument();
setDocument(doc);
// Finally, read the date from the stream
getEditorKit().read(reader, doc, 0);
}
/*
* Description -setTextInput - text to display
* @param - String sText - text to display
*
*/
public void setTextInput(String sText) throws IOException,
BadLocationException {
String type; // = guessContentType(is);
//if (type == null) {
// Unknown type - use plain text
type = "text/html";
//}
//System.out.println("File content type is " + type);
// Set the new content type
setContentType(type);
// Now create the appropriate document and install it
Document doc = getEditorKit().createDefaultDocument();
setDocument(doc);
setText(sText);
// Finally, read the date from the stream
//getEditorKit().read(reader, doc, 0);
}
/*
* Description -method to look at input and try to determine if it is text, html, rtf
* @param - InputStream - set up by calling object
*/
// Guess the content type
protected String guessContentType(InputStream is) throws IOException {
String type = URLConnection.guessContentTypeFromStream(is);
if (type == null) {
is.mark(10);
int c1 = is.read();
int c2 = is.read();
int c3 = is.read();
int c4 = is.read();
int c5 = is.read();
is.reset();
if (c1 == '{' && c2 == '\\' && c3 == 'r' && c4 == 't'
&& c5 == 'f') {
type = "text/rtf";
}
// Add more heuristics here
}
return type;
}
/*
* Description -MAIN method to test this class
*
*/
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("Please supply the name of a file to read");
System.exit(1);
}
try {
InputStream is = new BufferedInputStream(new FileInputStream(args[0]));
JFrame f = new JFrame("StreamEditorPane Example");
StreamEditorPane ep = new StreamEditorPane();
f.getContentPane().add(ep);
f.setSize(400, 400);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
f.setVisible(true);
// Load the data from the stream
ep.setInputStream(is);
} catch (FileNotFoundException e) {
System.out.println("Failed to open file " + args[0]);
System.exit(1);
} catch (IOException e) {
System.out.println("Error while reading file " + args[0]);
System.exit(1);
} catch (Throwable t) {
System.out.println("Unexpected exception: " + t);
System.exit(1);
}
}
}