program design request

P

Peter

hi
All the classes of my java program in packed into a single jar
file. I want my program able to download the updated class file and
replace it to old class file in jar. But if i do this, i need to
restart the program to let the new class file activate. Do you have
any solution can work arround it?

My goal is to let my program auto-update through internet and
without restart to let new function activate.

thanks
from Peter([email protected])
 
A

Andrew Thompson

All the classes of my java program in packed into a single jar
file. I want my program able to download the updated class file and
replace it to old class file in jar. But if i do this, i need to
restart the program to let the new class file activate. Do you have
any solution can work arround it?

Adjust your thinking. Many programs (under Windows) will
force a system reboot on updates, if you tell the user they
need to stop and restart the program to get the updated version,
they will probably be happy they do not have to reboot.
My goal is to let my program auto-update through internet

A task for which JWS is well suited.
..and without restart to let new function activate.

Why do you think your program needs this?

--
Andrew Thompson
http://www.PhySci.org/codes/ Web & IT Help
http://www.PhySci.org/ Open-source software suite
http://www.1point1C.org/ Science & Technology
http://www.lensescapes.com/ Images that escape the mundane
 
C

Chris Smith

Peter said:
All the classes of my java program in packed into a single jar
file. I want my program able to download the updated class file and
replace it to old class file in jar. But if i do this, i need to
restart the program to let the new class file activate. Do you have
any solution can work arround it?

My goal is to let my program auto-update through internet and
without restart to let new function activate.

You can't directly replace code that's already been loaded. What you
can do is load new code, and arrange to use the new code instead. For
example, if you want to check for updates when the application is
executed, try this:

1. Write a small loader module that's loaded by the system classloader.
2. Package your real application into a separate JAR file, loaded by a
separate classloader.
3. Check for updates before loading the real application. If there is
an update, you can modify the JAR file *before* you load it.

There are also APIs for replacing a function at a time, but they are
intended for debugging purposes, they don't always work (which is okay
in an interactive debugging environment), and they aren't suitable for
production code.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
P

Peter

Andrew Thompson said:
Adjust your thinking. Many programs (under Windows) will
force a system reboot on updates, if you tell the user they
need to stop and restart the program to get the updated version,
they will probably be happy they do not have to reboot.


A task for which JWS is well suited.


Why do you think your program needs this?

Hi
If it is a non-stop database, then i probably need that.
thanks
from Peter
 
J

Jesper Nordenberg

Hi
If it is a non-stop database, then i probably need that.

Updating a database application that is running sounds extremely
dangerous. Data structures in memory might change with the update
causing all kinds of inconsistencies. I think your best option is to
create a small application that acts as server to the database
clients. This application communicates with the real database
application and forwards data from the clients to the database and
from the database to the clients. That way you can shutdown, update
and restart the database application without breaking any client
connections. The middle application just needs to reconnect with the
database application when it starts again.

/Jesper Nordenberg
 
S

steve

You can't directly replace code that's already been loaded. What you
can do is load new code, and arrange to use the new code instead. For
example, if you want to check for updates when the application is
executed, try this:

1. Write a small loader module that's loaded by the system classloader.
2. Package your real application into a separate JAR file, loaded by a
separate classloader.
3. Check for updates before loading the real application. If there is
an update, you can modify the JAR file *before* you load it.

There are also APIs for replacing a function at a time, but they are
intended for debugging purposes, they don't always work (which is okay
in an interactive debugging environment), and they aren't suitable for
production code.

1. yes you CAN RELOAD CODE that has already been loaded. ( as long as you are
not executing it) , check the sun website there is a working demo
2. it is very easy to do this, but there is 1 small problem , you cannot
update your base class loader easily.

3. split out your jars, that way you can update them on windows, once the
program is started.

4. you can replace the class files , but it means you have to unpack the jar
, remove the class, then put a new one back it, I recommend you work on a JAR
level , not a class level), at a jar level , you Know the jar works because
it compiled. If you use Classes, you have to be 100% sure that every
referenced class is also updated.

the main problem is WINDOWS machines, once you start execution of a jar,
windows marks the whole jar as in use, so you cannot make changes to it.

mac /linux, do not do this!!, you can actually move/rename a file whilst it
is in use, and make copies changes.


The way i do this is:
1. have a properties file.
in the properties file have:
A. Your working class path
B. the system classpath.
C your main program entry point.


here is my example file


loadThisClass=RootClassFrame.RootClassFrame

OurClassPath=MainProgram.jar,ReportWriter.jar,nls_charset12.zip,classes12.zip,
jasperreports-0.6.1.jar,commons-digester-1.3.jar,commons-collections-
2.1.jar,log4j-1.2.8.jar,commons-logging-1.0.2.jar,commons-beanutils-
1.5.jar,bsh-1.3.0.jar,poi-2.0-final-
20040126.jar,servlet.jar,xalan.jar,xercesImpl.jar,xmlParserAPIs.jar,hsqldb-
1.61.jar,itext-1.02b.jar,jung.jar,commons-collections-3.1.jar,colt.jar

SystemClassPath=jasperreports-0.6.1.jar


now the bootloader code.

this program starts by looking in the current directory for any files that
start with "_NEW", and then removes the old jar to replace it with the new
one

then it takes the main class name from the properties file & this starts a
new thread, and loads the main program class.
the main class looks for updates on a server , and downloads them. ( adds a
"new_" to the start of the file , then Quits the program.

However you must ensure that the bootloader jar is NOT in your main jar
package, otherwise when windows launches the java , it LOCKS the .jar file,
that you launch.
so basically at this stage only the bootloader is locked, so we can use it to
add/change/rename files.


the code is useful to you because it is:
1. a Working example , ( currently it sits on about 50 workstations, being
used daily)
2. shows how to play with the system & your own classpath , ( you can still
execute stuff not in the system classpath, by passing your own classpath to
the class loader)

3.but note that it does not , allow the program to continue execution, it
requires a re-start.

to get your continued execution, depends on what extra classes you add into
your program, If it is changes to the GUI, then no amount of trickery ,is
going to update your GUI , by loading new classes.
You would have to throw your GUI away and regenerate it, you may as well just
do a restart of the program.
if it is just to background code ,then it is very easy, just change your
"user classpath" to add in the extra jars,, then call the new classes, via a
NEW classloader , and it will work.








package bootLoader;


//this has become more of a generic boot loader
//it gets the class path from a properties file
// our first class needs to be called "launch_me"
//the properties file comes from the program file.
import java.io.*;

import java.lang.reflect.Method;

import java.net.URL;
import java.net.URLClassLoader;

import java.util.StringTokenizer;


public class bootLoader extends ClassLoader {
private static String loadThisClass = ""; //
"RootClassFrame.RootClassFrame";
private static String OurClassPath1 = "";
private static String SystemClassPath = "";

// private static String loadThisClass2 =
"net.sf.jasperreports.engine.JasperFillManager";
private static String TempPrefix = "new_"; //this holds an extension so
we can downloade without overwriting
private static String backupPrefix = "old_"; //this holds an extension so
we can downloade without overwriting
private static String ourProgramDirectory;
public static URL[] OurClassPath;
private static String classPath;

public static void main(String[] args) throws Exception {
Method mainMethod;
Class toRun;

try {
ourProgramDirectory = System.getProperty("user.dir");
String filesep = File.separator;

//due to a shitty implementation of java in windows we cannot
rename the files that contain the class info
// therefore we look for any files in the current directory that
have a "new_" prefix & replace them.
reNamer();

//we need to trap for errors here
java.util.Properties props = new java.util.Properties();

// java.net.URL url =
ClassLoader.getSystemResource("Theprog.props");
java.io.FileInputStream fis =
new java.io.FileInputStream(new
java.io.File("Theprog.props"));
props.load(fis);
fis.close();

//now read in our properties file
loadThisClass = (props.getProperty("loadThisClass"));
OurClassPath1 = (props.getProperty("OurClassPath"));
SystemClassPath = (props.getProperty("SystemClassPath"));

//(Integer.parseInt(props.getProperty("logLevel")));
// File dir = new File(new File(".").getCanonicalPath());

//this is our new class loader that does not need the classpath
set.
//but we do need an array with files in ( we need to put this
shit in a properties file)
StringTokenizer st = new StringTokenizer(OurClassPath1, ",");
int aa = st.countTokens();
OurClassPath = new URL[aa];

int loop = 0;

while (st.hasMoreTokens()) {
URL x1 =
new URL("file:" + ourProgramDirectory + filesep +
st.nextToken());
OurClassPath[loop] = x1;
loop++;
}


String classPath =
System.getProperties().getProperty("java.class.path", ".");

st = new StringTokenizer(SystemClassPath, ",");
loop = 0;

String it = "";

while (st.hasMoreTokens()) {
it = filesep + st.nextToken() + ":";
loop++;
}

classPath = it + classPath;
System.getProperties().setProperty("java.class.path", classPath);

//
System.out.println(System.getProperties().getProperty("java.class.path",
"."));
ClassLoader loader = new URLClassLoader(OurClassPath);

//force the threads classloader to the url loader
Thread.currentThread().setContextClassLoader(loader);

// toRun = loader.loadClass(loadThisClass);
toRun =
Thread.currentThread().getContextClassLoader().loadClass(loadT
hisClass);
// String[] newArgs = scrubArgs(args);
mainMethod = findMain(toRun);

//debug to print class loaders
ClassLoader current =
Thread.currentThread().getContextClassLoader();

while (current != null) {
System.out.println("load---" + current.getClass());
current = current.getParent();
}

if (mainMethod != null) {
mainMethod.invoke(null, new Object[] { args });

// mainMethod.invoke(null, new object[] { });
} else {
System.out.println("There is no MAIN (String Args[]) to run
");
}
} catch (Exception e) {
System.out.println(
"Exception Caused when trying to load main Class");
e.printStackTrace();
}
}

private static void reNamer() {
//this is real sloppy code it relies on the files starting with
"new_"
String prefixFreeName = "";
String filename = "";

System.out.println("Entered renamer user.dir is: " +
ourProgramDirectory);

try {
File dir = new File(ourProgramDirectory);
String[] children;

//children = dir.list();
// It is also possible to filter the list of returned files.
// This example does not return any files that start with `.'.
FilenameFilter filter =
new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith(TempPrefix);
}
};

children = dir.list(filter);

if (children == null) {
// Either dir does not exist or is not a directory
} else {
for (int i = 0; i < children.length; i++) {
// Get filename of file or directory
filename = children;

//get the filename minus the last 4 characters
prefixFreeName = filename.substring(4,
filename.length());

//we need some error checking here
if (!(0 == ("bootloader.jar".compareToIgnoreCase(
prefixFreeName)))) {
//check if the backup exists first!!
if (new File(backupPrefix + prefixFreeName).exists())
{
// if yes delete it
new File(backupPrefix + prefixFreeName).delete();
//delete any old copies first
}

//check if the current file exists
if (new File(prefixFreeName).exists()) {
if (renamefile(prefixFreeName,
(backupPrefix + prefixFreeName)))
//do the old program file
{
;
} else {
System.out.println("Failed to rename old file
" +
"---" + prefixFreeName + "---to---" +
backupPrefix + prefixFreeName);
}
}

//finally rename the new file to the existing name
if (renamefile(filename, prefixFreeName)) {
;
} else {
System.out.println("Failed to rename new file " +
"---" + filename + "---to---" +
prefixFreeName);
}
} else {
//the file was named boot loader it is a special case
//we need some sort of message to the user to tell
them to rename the bootloader.
;
}
}
}
} catch (Exception e) {
System.out.println("Exception caused Failed to rename a file ");
}
}

private static boolean renamefile(String oldfile, String newfile) {
boolean success = false;

// File (or directory) with old name
File file = new File(oldfile);

// File (or directory) with new name
File file2 = new File(newfile);

// Rename files ONLY
if (!file.isDirectory() && !file2.isDirectory()) {
success = file.renameTo(file2);
}

return success;
}

private static Method findMain(Class passedClass) throws Exception {
Method[] methods = passedClass.getMethods();

for (int i = 0; i < methods.length; i++) {
if (methods.getName().equals("main")) {
return methods;
}
}

return null;
}
}

steve
 
S

steve

(e-mail address removed) (Peter) wrote in message


Updating a database application that is running sounds extremely
dangerous. Data structures in memory might change with the update
causing all kinds of inconsistencies. I think your best option is to
create a small application that acts as server to the database
clients. This application communicates with the real database
application and forwards data from the clients to the database and
from the database to the clients. That way you can shutdown, update
and restart the database application without breaking any client
connections. The middle application just needs to reconnect with the
database application when it starts again.

/Jesper Nordenberg

nope that is a bad idea, you are adding an extra layer of code and creating
a bottle neck, imagine 200 clients putting requests thru 1 communication
application.

I am using an auto update program, that downloads the updated program parts
from the database.
the said program also is the database client.
But I will say a Re-start is 100% better than continued execution.

as for breaking connections, I use the oracle connection pool, I do not
leave a connection open.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top