Author
how to hot deploy jar files
chris liao
Greenhorn
Joined: Jul 24, 2005
Posts: 26
I am in trouble, and very painful! My boss want me to design hot deploy for his application,which is a small java server and need hot-deploy jars But,util now, i don't know about hot-deploy! Hand-masters,please help me, What should i do ? write some classLoader or other? I hope you give me some very userful source code. Thanks!
chris liao
Greenhorn
Joined: Jul 24, 2005
Posts: 26
for this, I wrote a classLoader, below is source code: package org.jmin.bridge.loader; import java.io.*; import java.net.*; import java.util.*; import org.jmin.bridge.deploy.*; import org.jmin.bridge.config.*; import org.jmin.logger.Logger; public class RuntimeLoader extends URLClassLoader{ private static Logger logger = Logger.getLogger(RuntimeLoader.class); private static RuntimeLoader loader = null; private static List urlList = new LinkedList (); public static RuntimeLoader getClassLoader(){ if(loader == null){ loader= new RuntimeLoader(AutoDetector.getInstance().getURLs(), getSystemClassLoader()); } else { URL[] urls = AutoDetector.getInstance().getURLs(); for(int i=0;i < urls.length;i++){ loader.addURL(urls[i]); } } return loader; } public RuntimeLoader(URL[] urls) { super(urls); } public Class loadClass(String clsname) throws ClassNotFoundException { return super.loadClass(clsname); } private List getList(){ if(urlList == null) urlList = new LinkedList (); return urlList; } public RuntimeLoader(URL[] urls,ClassLoader parent) { super(urls,parent); } public RuntimeLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) { super(urls,parent,factory); } public void addURL(URL url) { if(!getList().contains(url)){ logger.debug("add url: " +url); super.addURL(url); getList().add(url); } } protected void finalize() throws Throwable{ super.finalize(); } private ClassLoader getParentClassLoader(){ if(loader == null) return (OBClassLoader.class).getClassLoader(); else return loader; } public static ClassLoader getSystemClassLoader(){ return (OBClassLoader.class).getClassLoader(); } }
chris liao
Greenhorn
Joined: Jul 24, 2005
Posts: 26
and I wrote a Detector, source code is below: package org.jmin.bridge.deploy; import java.io.*; import java.net.*; import java.util.*; import org.jmin.bridge.util.*; import org.jmin.bridge.config.*; import org.jmin.bridge.core.*; import org.jmin.bridge.loader.*; import org.jmin.bridge.common.*; import org.jmin.bridge.server.*; import org.jmin.logger.Logger; public class AutoDetector extends Thread { private static Logger logger = Logger.getLogger(AutoDetector.class); private static String deployFolder = null; private static String workFolder = null; private static int PoolDetectTime =0; private static AutoDetector deploy = null; private File detectFolder = null; private List currentFileList = null; private List lastFileList = null; private Map urlMap = null; private Map fileServiceMap = null; private Thread fatherThread = null; static{ PoolDetectTime = Config.getInstance(). getInt(ConfigKey.KEY_Thread_Pool_Detect_Time, ConfigConstants.Thread_Pool_Detect_Time); deployFolder = Config.getInstance(). getString( ConfigKey.KEY_Deploy_Path); workFolder = Config.getInstance(). getString( ConfigKey.KEY_Work_Path); deployFolder = "D:\\bridge\\deploy";// test workFolder = "D:\\bridge\\work";//test if(Util.isNull(deployFolder)&& CurrentRole.isServerRole()){ deployFolder = getDeployPath(); } if(Util.isNull(workFolder)&& CurrentRole.isServerRole()){ workFolder = getWorkPath(); } if(!Util.isNull(deployFolder) && !deployFolder.endsWith("\\")){ deployFolder = deployFolder +"\\"; } if(!Util.isNull(workFolder) && !workFolder.endsWith("\\")){ workFolder = workFolder +"\\"; } } public static AutoDetector getInstance(){ if(deploy == null) deploy = new AutoDetector(); return deploy; } public AutoDetector() { this.prepare(); this.currentFileList = new LinkedList (); this.lastFileList = new LinkedList (); this.urlMap = new Hashtable(); this.fileServiceMap = new Hashtable(); this.fatherThread = Thread.currentThread(); if(!Util.isNull(workFolder) && !Util.isNull(workFolder)){ this.start(); } } private void prepare(){ detectFolder = new File(deployFolder); if(!detectFolder.exists()&& CurrentRole.isServerRole()){ detectFolder.mkdirs(); } File work = new File(workFolder); if(!work.exists()&& CurrentRole.isServerRole()){ work.mkdirs(); }else{ File[] files = work.listFiles(); for(int i =0;i<files.length;i++) files[i].delete(); } } public void run(){ ThreadPool.getInstance().push(fatherThread,this); while(fatherThread.isAlive()){ this.getDeployFileList(); this.detectNewFile(); this.detectDelFile(); this.detectUpdateFile(); this.storeDeployFileList(); this.wait(PoolDetectTime); } } private void wait(int time){ try{ Thread.sleep(time); }catch(Exception e){ } } private void detectNewFile(){ for(int i =0;i< currentFileList.size();i++){ if(!lastFileList.contains(currentFileList.get(i))){ try{ FilePair file = (FilePair)currentFileList.get(i); String filename = file.getFileName(); String wkFile = concludeWkPath(filename); this.copyFile(file.getFile(),wkFile); logger.debug("deploy file: " + filename); Map map = XMLParser.parse(wkFile); addNewService(filename,map); addNewURL(filename,new File(wkFile).toURL()); }catch(Exception e){ e.printStackTrace(); } } } } private void addNewURL(String filename,URL ulr){ urlMap.put(filename,ulr); } private void removeURL(String filename){ urlMap.remove(filename); } private void detectDelFile(){ for(int i =0;i< lastFileList.size();i++){ if(!currentFileList.contains(lastFileList.get(i))){ FilePair file = (FilePair)lastFileList.get(i); String filename = file.getFileName(); removeService(filename); removeURL(filename); logger.debug("undeploy file: " + filename); } } } private void detectUpdateFile(){ for(int i=0; i < lastFileList.size();i++){ try{ FilePair lastFile = (FilePair)lastFileList.get(i); FilePair currentFile = getCurrentFile(lastFile); if(currentFile != null && (currentFile.isModified(lastFile))){ String filename = currentFile.getFileName(); logger.debug("redeploy file: " + filename); String wkFile = concludeWkPath(filename); this.copyFile(currentFile.getFile(),wkFile); Map map = XMLParser.parse(wkFile); addNewService(filename,map); addNewURL(filename,new File(wkFile).toURL()); } }catch(Exception e){ } } } private FilePair getCurrentFile(FilePair pair){ FilePair currentPair = null; for(int i = 0;i < currentFileList.size();i++){ FilePair temp = (FilePair)currentFileList.get(i); if(temp.equals(pair)){ currentPair = temp; break; } } return currentPair; } private synchronized void getDeployFileList(){ currentFileList.clear(); File[] files = detectFolder.listFiles(); for(int i = 0;i < files.length;i++){ if(files[i].getName().endsWith("jar") || files[i].getName().endsWith("zip")){ currentFileList.add(new FilePair(files[i])); } } } private void storeDeployFileList(){ this.lastFileList.clear(); this.lastFileList.addAll(currentFileList); } private String concludeWkPath(String shortname){ return workFolder + Counter.getValue()+ shortname; } private void copyFile(File deployJar, String file2) throws IOException ,FileNotFoundException{ FileInputStream deployjar = new FileInputStream (deployJar); FileOutputStream workjar = new FileOutputStream (file2); while(true){ int byteValue = deployjar.read(); if(byteValue == -1) break; workjar.write(byteValue); } workjar.close(); deployjar.close(); } private static String getDeployPath(){ String path = CurrentRole.getAppPath(); if(!path.substring(path.length()).equals("\\")){ path = path + "\\"; } path = path + "deploy"; File deployDict = new File(path); if(!deployDict.exists()){ logger.debug("create folder: " + path); deployDict.mkdirs(); } return path; } private static String getWorkPath(){ String path = CurrentRole.getAppPath(); if(!path.substring(path.length()).equals("\\")){ path = path + "\\"; } path = path + "work"; File workDict = new File(path); if(!workDict.exists()){ logger.debug("create folder: " + path); workDict.mkdirs(); } return path; } private void addNewService(String file, Map newMap){ removeService(file); fileServiceMap.put(file,newMap); addServiceToManager(newMap); } private void removeService(String file){ Map oldMap = (Map)fileServiceMap.get(file); if(oldMap != null){ removeServiceFromManager(oldMap); fileServiceMap.remove(file); } } private void addServiceToManager(Map map){ Iterator it = map.entrySet().iterator(); while(it.hasNext()){ Map.Entry entry = (Map.Entry)it.next(); String key = (String)entry.getKey(); String value = (String)entry.getValue(); ServiceManager.getInstance().addServiceClass(key,value); } } private void removeServiceFromManager(Map map){ Iterator it = map.entrySet().iterator(); while(it.hasNext()){ Map.Entry entry = (Map.Entry)it.next(); String key = (String)entry.getKey(); ServiceManager.getInstance().remove(key); } } private synchronized Collection getWorkFileList(){ return urlMap.values(); } public URL[] getURLs(){ Collection col = getWorkFileList(); URL[] arry = new URL[col.size()]; Iterator it = col.iterator(); int i = 0; while(it.hasNext()){ arry[i]=(URL)it.next(); } return arry; } } class Counter { private static long value = 1; public static long getValue(){ return value++; } }
chris liao
Greenhorn
Joined: Jul 24, 2005
Posts: 26
when load some class: ClassNotFoundException is throwed.
Tony Morris
Ranch Hand
Joined: Sep 24, 2003
Posts: 1608
posted Jul 27, 2005 17:31:00
0
I didn't go through your code, but "hot loading" (definition assumed) is really quite easy. The main point is that you must load classes with a new class loader each time you use the, since classes cannot be unloaded from class loaders, and so they cannot be redefined within the same class loader.
Tony Morris
Java Q&A (FAQ, Trivia)
Stan James
(instanceof Sidekick)
Ranch Hand
Joined: Jan 29, 2003
Posts: 8791
Anyone know if you must write a custom class loader to do this? I dug through JUnit to find the one it uses and it is pretty simple, but I didn't try to figure out why they needed a custom one at all. What's a common way to make a whole application start using a new class loader? If you're doing plain old "new Object()" all over the place you'll just keep using the loader that loaded the class you're in, right? Do you need a global loader or a factory that knows when laoders change?
A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
subject: how to hot deploy jar files