/* * Copyright 2013 * * 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 org.openntf.domino.design.impl; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import org.openntf.domino.design.DatabaseDesign; import org.openntf.domino.design.XspResource; import org.openntf.domino.utils.DominoUtils; /** * @author jgallagher * */ public class DatabaseClassLoader extends org.openntf.domino.design.DatabaseClassLoader { @SuppressWarnings("unused") private static final Logger log_ = Logger.getLogger(DatabaseClassLoader.class.getName()); private final Map<String, byte[]> unloadedClasses_ = new HashMap<String, byte[]>(); private final boolean includeJars_; private boolean loadedJars_ = false; private final boolean includeLibraries_; private boolean loadedLibraries_ = false; private final DatabaseDesign design_; public DatabaseClassLoader(final DatabaseDesign design, final ClassLoader parent, final boolean includeJars, final boolean includeLibraries) { super(parent); design_ = design; includeJars_ = includeJars; includeLibraries_ = includeLibraries; } @Override protected Class<?> findClass(final String name) throws ClassNotFoundException { // Check if it's in our pool of in-process classes if (unloadedClasses_.containsKey(name)) { byte[] classData = unloadedClasses_.remove(name); return defineClass(name, classData, 0, classData.length); } String binaryName = DominoUtils.escapeForFormulaString(DominoUtils.javaBinaryNameToFilePath(name, "/")); Iterator<XspResource> classes = design_.getDesignElements(XspResource.class, String.format("$ClassIndexItem='WEB-INF/classes/%s' ", binaryName)).iterator(); if (classes.hasNext()) { XspResource res = classes.next(); // Load up our class queue with the data unloadedClasses_.putAll(res.getClassData()); // Now attempt to load the named class byte[] classData = unloadedClasses_.remove(name); if (classData != null) { // It's possible that an old name of the Java class is still lingering in the NSF // In that case, we'd reach this point, but not have an actual class available to load return defineClass(name, classData, 0, classData.length); } } // It's also possible that it's stored only as a .class file (e.g. secondary, non-inner classes in a .java) Iterator<FileResourceWebContent> webContentFiles = design_.getDesignElements(FileResourceWebContent.class, String.format("$FileNames='WEB-INF/classes/%s' ", binaryName)).iterator(); if (webContentFiles.hasNext()) { FileResourceWebContent res = webContentFiles.next(); byte[] classData = res.getFileData(); return defineClass(name, classData, 0, classData.length); } // TODO consider changing the below routines to only loop through resources until found, // keeping track of which libraries have been loaded // If we're here, see if we should look through the Jars - load them all now if (includeJars_ && !loadedJars_) { for (org.openntf.domino.design.JarResource jar : design_.getJarResources()) { System.out.println(jar.getName()); unloadedClasses_.putAll(jar.getClassData()); } loadedJars_ = true; if (unloadedClasses_.containsKey(name)) { byte[] classData = unloadedClasses_.remove(name); return defineClass(name, classData, 0, classData.length); } } // Now do the same for Java script libraries if (includeLibraries_ && !loadedLibraries_) { for (org.openntf.domino.design.ScriptLibraryJava lib : design_.getScriptLibrariesJava()) { System.out.println(lib.getName()); Map<String, byte[]> classData = lib.getClassData(); unloadedClasses_.putAll(classData); } loadedLibraries_ = true; if (unloadedClasses_.containsKey(name)) { byte[] classData = unloadedClasses_.remove(name); return defineClass(name, classData, 0, classData.length); } } return super.findClass(name); } @Override public Set<Class<?>> getClassesWithAnnotation(final Class<? extends Annotation> annotationClass) { Set<Class<?>> result = new LinkedHashSet<Class<?>>(); for (String className : design_.getJavaResourceClassNames()) { try { Class<?> clazz = loadClass(className); if (clazz.getAnnotation(annotationClass) != null) { result.add(clazz); } } catch (ClassNotFoundException e) { // Ignore - Java resources keep copies of their old names, tripping up the search } } return result; } @SuppressWarnings("unchecked") @Override public <T> Set<Class<? extends T>> getClassesExtending(final Class<T> superClass) { Set<Class<? extends T>> result = new LinkedHashSet<Class<? extends T>>(); for (String className : design_.getJavaResourceClassNames()) { try { Class<?> clazz = loadClass(className); if (superClass.isAssignableFrom(clazz)) { result.add((Class<? extends T>) clazz); } } catch (ClassNotFoundException e) { // Ignore - Java resources keep copies of their old names, tripping up the search } } return result; } @Override public org.openntf.domino.design.DatabaseDesign getParentDesign() { return design_; } }