Java tutorial
/** * Squidy Interaction Library is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * Squidy Interaction Library is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Squidy Interaction Library. If not, see * <http://www.gnu.org/licenses/>. * * 2009 Human-Computer Interaction Group, University of Konstanz. * <http://hci.uni-konstanz.de> * * Please contact info@squidy-lib.de or visit our website * <http://www.squidy-lib.de> for further information. */ package org.squidy.common.dynamiccode; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * <code>HotDeployClassLoader</code>. * * <pre> * Date: Aug 21, 2009 * Time: 12:32:25 PM * </pre> * * * @author Roman Rdle <a * href="mailto:Roman.Raedle@uni-konstanz.de">Roman.Raedle * @uni-konstanz.de</a> Human-Computer Interaction Group University of * Konstanz * * @version $Id: HotDeployClassLoader.java 772 2011-09-16 15:39:44Z raedle $ * @since 1.0.0 */ public class HotDeployClassLoader extends ClassLoader { // Logger to log info, error, debug,... messages. private static final Log LOG = LogFactory.getLog(HotDeployClassLoader.class); private Map<String, ClassHolder> classTimeStamps; private List<String> classesToDelegate; private Map<String, RuntimeClassLoader> runtimeClassLoaders; /** * @param classLoader */ public HotDeployClassLoader(ClassLoader classLoader) { super(classLoader); classTimeStamps = new HashMap<String, ClassHolder>(); classesToDelegate = new ArrayList<String>(); runtimeClassLoaders = new HashMap<String, RuntimeClassLoader>(); } /** * @param name */ public void addClassToDelegateList(String name) { classesToDelegate.add(name); } /** * @param name * @return */ protected boolean isClassInDelagationList(String name) { return classesToDelegate.contains(name); } /* (non-Javadoc) * @see java.lang.ClassLoader#findClass(java.lang.String) */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { if (!isClassAvailable(name)) { // if (LOG.isDebugEnabled()) { // LOG.debug("Needs loading " + name); // } if (!runtimeClassLoaders.containsKey(name)) { createRuntimeClassLoader(name); } return runtimeClassLoaders.get(name).loadClass(name); } if (isNewerVersionAvailable(name)) { if (LOG.isDebugEnabled()) { LOG.debug("Newer version required for " + name); } classTimeStamps.remove(name); createRuntimeClassLoader(name); return runtimeClassLoaders.get(name).loadClass(name); } if (LOG.isDebugEnabled()) { LOG.debug("Version is still up-to-date " + name); } return classTimeStamps.get(name).getClazz(); } /** * */ private void createRuntimeClassLoader(String name) { runtimeClassLoaders.put(name, new RuntimeClassLoader(this)); } /** * @param name * @return */ private boolean isClassAvailable(String name) { return classTimeStamps.containsKey(name); } /** * @param name * @return */ private boolean isNewerVersionAvailable(String name) { File file = new File(DynamicCodeClassLoader.DYNAMIC_CODE_REPOSITORY, name.replace(".", "/") + ".class"); return file.lastModified() > classTimeStamps.get(name).getTimeStamp(); } // /* (non-Javadoc) // * @see java.lang.ClassLoader#loadClass(java.lang.String) // */ // @Override // public Class<?> loadClass(String name) throws ClassNotFoundException { // return loadClass(name, false); // } @Override protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { return (isClassInDelagationList(name)) ? getParent().loadClass(name) : findClass(name); } /** * <code>ClassHolder</code>. * * <pre> * Date: Aug 21, 2009 * Time: 12:33:08 PM * </pre> * * * @author * Roman Rdle * <a href="mailto:Roman.Raedle@uni-konstanz.de">Roman.Raedle@uni-konstanz.de</a> * Human-Computer Interaction Group * University of Konstanz * * @version $Id: HotDeployClassLoader.java 772 2011-09-16 15:39:44Z raedle $ * @since 1.0.0 */ static class ClassHolder { private Class<?> clazz; private long timeStamp; public ClassHolder(Class<?> clazz, long timeStamp) { this.clazz = clazz; this.timeStamp = timeStamp; } public Class<?> getClazz() { return clazz; } public long getTimeStamp() { return timeStamp; } } /** * <code>RuntimeClassLoader</code>. * * <pre> * Date: Aug 21, 2009 * Time: 12:33:12 PM * </pre> * * * @author * Roman Rdle * <a href="mailto:Roman.Raedle@uni-konstanz.de">Roman.Raedle@uni-konstanz.de</a> * Human-Computer Interaction Group * University of Konstanz * * @version $Id: HotDeployClassLoader.java 772 2011-09-16 15:39:44Z raedle $ * @since 1.0.0 */ private class RuntimeClassLoader extends ClassLoader { /** * @param classLoader */ public RuntimeClassLoader(ClassLoader classLoader) { super(classLoader); } /* (non-Javadoc) * @see java.lang.ClassLoader#findClass(java.lang.String) */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { return loadClass(name); } /* (non-Javadoc) * @see java.lang.ClassLoader#loadClass(java.lang.String) */ public Class<?> loadClass(String name) throws ClassNotFoundException { if (isClassInDelagationList(name)) { return getParent().loadClass(name); } byte[] classBytes = null; try { classBytes = getBytes(name.replace(".", "/") + ".class"); } catch (IOException e) { return findSystemClass(name); } Class<?> clazz = defineClass(name, classBytes, 0, classBytes.length); File file = new File(DynamicCodeClassLoader.DYNAMIC_CODE_REPOSITORY, name.replace(".", "/") + ".class"); classTimeStamps.put(name, new ClassHolder(clazz, file.lastModified())); return clazz; } /** * @param filename * @return * @throws IOException */ private byte[] getBytes(String filename) throws IOException { File file = new File(DynamicCodeClassLoader.DYNAMIC_CODE_REPOSITORY, filename); long len = file.length(); byte raw[] = new byte[(int) len]; FileInputStream fin = new FileInputStream(file); int r = fin.read(raw); if (r != len) throw new IOException("Can't read all, " + r + " != " + len); fin.close(); return raw; } } }