/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package info.jtrac.wicket.devmode;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* used by ReloadingWicketFilter, see class level comment there
*/
public class ReloadingClassLoader extends URLClassLoader {
private static final Logger logger = LoggerFactory.getLogger(ReloadingClassLoader.class);
private List<Pattern> watchPatterns = new ArrayList<Pattern>();
private List<Pattern> ignorePatterns = new ArrayList<Pattern>();
private long lastReload;
private Set<Class> loadedClasses = new HashSet<Class>();
public ReloadingClassLoader(ClassLoader parent) {
super(new URL[]{}, parent);
lastReload = new Date().getTime();
Enumeration<URL> resources;
try {
resources = parent.getResources("");
} catch (IOException exception) {
throw new RuntimeException(exception);
}
while (resources.hasMoreElements()) {
addURL(resources.nextElement());
}
}
public void watch(String pattern) {
watchPatterns.add(Pattern.compile(pattern));
}
public void ignore(String pattern) {
ignorePatterns.add(Pattern.compile(pattern));
}
@Override
public Class loadClass(String name) throws ClassNotFoundException {
Class clazz = findLoadedClass(name);
if (clazz != null) {
return clazz;
}
if (mustWatch(name)) {
try {
// logger.debug("loading reloadable class: " + name);
clazz = super.findClass(name);
loadedClasses.add(clazz);
} catch (ClassNotFoundException exception) {
logger.error(exception.getMessage());
}
}
if (clazz == null && getParent() != null) {
clazz = getParent().loadClass(name);
}
if (clazz == null) {
throw new ClassNotFoundException(name);
}
return clazz;
}
public boolean hasChanges() {
for (Class clazz : loadedClasses) {
String classRelativeFile = clazz.getName().replaceAll("\\.", "/") + ".class";
for (URL url : getURLs()) {
File classAbsoluteFile = new File(url.getFile() + classRelativeFile);
if (classAbsoluteFile.exists() && classAbsoluteFile.lastModified() > lastReload) {
logger.debug("change detected for file: " + clazz.getCanonicalName());
return true;
}
}
}
return false;
}
@Override
public ReloadingClassLoader clone() {
ReloadingClassLoader clone = new ReloadingClassLoader(getParent());
clone.ignorePatterns = ignorePatterns;
clone.watchPatterns = watchPatterns;
return clone;
}
private boolean mustWatch(String name) {
for (Pattern pattern : watchPatterns) {
if (pattern.matcher(name).matches()) {
for (Pattern pattern_ : ignorePatterns) {
if (pattern_.matcher(name).matches()) {
return false;
}
}
return true;
}
}
return false;
}
}