Index: stripes/src/net/sourceforge/stripes/exception/DelegatingExceptionHandler.java =================================================================== --- stripes/src/net/sourceforge/stripes/exception/DelegatingExceptionHandler.java (revision 1119) +++ stripes/src/net/sourceforge/stripes/exception/DelegatingExceptionHandler.java (working copy) @@ -14,11 +14,13 @@ */ package net.sourceforge.stripes.exception; +import net.sourceforge.stripes.action.ActionBean; import net.sourceforge.stripes.config.BootstrapPropertyResolver; import net.sourceforge.stripes.config.Configuration; import net.sourceforge.stripes.controller.AnnotatedClassActionResolver; import net.sourceforge.stripes.util.Log; import net.sourceforge.stripes.util.ResolverUtil; +import net.sourceforge.stripes.util.ResolverUtilFactory; import net.sourceforge.stripes.util.StringUtil; import javax.servlet.http.HttpServletRequest; @@ -146,7 +148,7 @@ } if (packages != null && packages.length > 0) { - ResolverUtil resolver = new ResolverUtil(); + ResolverUtil resolver = ResolverUtilFactory.newInstance(AutoExceptionHandler.class); resolver.findImplementations(AutoExceptionHandler.class, packages); return resolver.getClasses(); } Index: stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java =================================================================== --- stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java (revision 1119) +++ stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java (working copy) @@ -28,6 +28,7 @@ import net.sourceforge.stripes.util.HttpUtil; import net.sourceforge.stripes.util.Log; import net.sourceforge.stripes.util.ResolverUtil; +import net.sourceforge.stripes.util.ResolverUtilFactory; import net.sourceforge.stripes.util.StringUtil; import javax.servlet.http.HttpServletRequest; @@ -670,7 +671,7 @@ } String[] pkgs = StringUtil.standardSplit(packages); - ResolverUtil resolver = new ResolverUtil(); + ResolverUtil resolver = ResolverUtilFactory.newInstance(ActionBean.class); resolver.findImplementations(ActionBean.class, pkgs); return resolver.getClasses(); } Index: stripes/src/net/sourceforge/stripes/config/BootstrapPropertyResolver.java =================================================================== --- stripes/src/net/sourceforge/stripes/config/BootstrapPropertyResolver.java (revision 1119) +++ stripes/src/net/sourceforge/stripes/config/BootstrapPropertyResolver.java (working copy) @@ -23,10 +23,12 @@ import java.util.Set; import javax.servlet.FilterConfig; +import net.sourceforge.stripes.action.ActionBean; import net.sourceforge.stripes.exception.StripesRuntimeException; import net.sourceforge.stripes.util.Log; import net.sourceforge.stripes.util.ReflectUtil; import net.sourceforge.stripes.util.ResolverUtil; +import net.sourceforge.stripes.util.ResolverUtilFactory; import net.sourceforge.stripes.util.StringUtil; /** @@ -138,7 +140,7 @@ } else { // we didn't find it in web.xml so now we check any extension packages - ResolverUtil resolver = new ResolverUtil(); + ResolverUtil resolver = ResolverUtilFactory.newInstance(targetType); String[] packages = StringUtil.standardSplit(getProperty(PACKAGES)); resolver.findImplementations(targetType, packages); Set> classes = resolver.getClasses(); @@ -200,7 +202,7 @@ */ public List> getClassPropertyList(Class targetType) { - ResolverUtil resolver = new ResolverUtil(); + ResolverUtil resolver = ResolverUtilFactory.newInstance(targetType); String[] packages = StringUtil.standardSplit(getProperty(PACKAGES)); resolver.findImplementations(targetType, packages); Set> classes = resolver.getClasses(); Index: stripes/src/net/sourceforge/stripes/util/ResolverUtilFactory.java =================================================================== --- stripes/src/net/sourceforge/stripes/util/ResolverUtilFactory.java (revision 0) +++ stripes/src/net/sourceforge/stripes/util/ResolverUtilFactory.java (revision 0) @@ -0,0 +1,66 @@ +/* Copyright 2009 Tony Dalbrekt + * + * 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 net.sourceforge.stripes.util; + +/** + * Factory to create an instance of {@link ResolverUtil} or a subclass of it depending on in which + * container the application is deployed. + * + * @see ResolverUtil + * @see WebSphereResolverUtil + * @author Tony Dalbrekt + */ +public class ResolverUtilFactory { + private static final Log log = Log.getInstance(ResolverUtilFactory.class); + + /** + * Hidden constructor. + */ + private ResolverUtilFactory() { + throw new UnsupportedOperationException("Not allowed to create an instance of this class"); + } + + /** + * Factory method to create correct instance of {@link ResolverUtil}. + *

+ * Uses the class loader {@code Thread.currentThread().getContextClassLoader()} by default. + *

+ * + * @param type of class to resolve + * @param type type of class to resolve + * @return a resolver + */ + public static ResolverUtil newInstance(Class type) { + return newInstance(type, Thread.currentThread().getContextClassLoader()); + } + + /** + * Factory method to create correct instance of {@link ResolverUtil} for a given class loader. + * + * @param type of class to resolve + * @param type type of class to resolve + * @param loader class loader for the resolver + * @return a resolver + */ + public static ResolverUtil newInstance(Class type, ClassLoader loader) { + if (WebSphereResolverUtil.isWebSphereClassLoader(loader)) { + log.trace("Creating resolver: ", WebSphereResolverUtil.class.getName()); + return new WebSphereResolverUtil(loader); + } + + log.trace("Creating resolver: ", ResolverUtil.class.getName()); + return new ResolverUtil(loader); + } +} Index: stripes/src/net/sourceforge/stripes/util/WebSphereResolverUtil.java =================================================================== --- stripes/src/net/sourceforge/stripes/util/WebSphereResolverUtil.java (revision 0) +++ stripes/src/net/sourceforge/stripes/util/WebSphereResolverUtil.java (revision 0) @@ -0,0 +1,158 @@ +/* Copyright 2009 Tony Dalbrekt + * + * 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 net.sourceforge.stripes.util; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Vector; + +/** + * WebSphere specific resolver to handle loading resources in JAR files. See {@link ResolverUtil} + * for more information. + *

+ * WebSphere can not load resources if the resource to load is a folder name, such as a + * package name, you have to explicit name a resource that is a file. Populate {@code resourcePaths} + * with the resources you want to load or if no {@code resourcePaths} are given the class scans the + * {@code WEB-INF/lib} for resources (jar files). + *

+ * + * @see ResolverUtil + * @see ResolverUtilFactory + * @author Tony Dalbrekt + */ +public class WebSphereResolverUtil extends ResolverUtil { + + private String[] resourcePaths; + + /** + * Constructor. + * + * @param resourcePaths resource paths to scan for classes + */ + public WebSphereResolverUtil(String[] resourcePaths) { + super(); + this.resourcePaths = resourcePaths; + } + + /** + * Constructor. + * + * @param classLoader the class loader to resolve classes from + */ + public WebSphereResolverUtil(ClassLoader classLoader) { + super(classLoader); + } + + /** + * Constructor. + * + * @param classLoader the class loader to resolve classes from + * @param resourcePaths resource paths to scan for classes + */ + public WebSphereResolverUtil(ClassLoader classLoader, String[] resourcePaths) { + super(classLoader); + this.resourcePaths = resourcePaths; + } + + /** + * Checks if the class loader is from IBM and thus the WebSphere platform? + * + * @param loader the class loader + * @return true if IBM class loader, else false + */ + public static boolean isWebSphereClassLoader(ClassLoader loader) { + return loader.getClass().getName().startsWith("com.ibm"); + } + + /** + * Gets the paths to the jar files that the resolver are about to scan for classes. + * + * @return array with jar file paths + */ + public String[] getResourcePaths() { + if (resourcePaths == null) { + resourcePaths = getJars(); + } + return resourcePaths; + } + + /** + * Collects and returns all the jar file paths in {@code WEB-INF/lib} from given class loader. + * + * @return an array with paths to jars, empty array if no one found + */ + protected String[] getJars() { + + URL resource = getClassLoader().getResource("WEB-INF/lib"); + + if (resource == null) { + return new String[0]; + } + + File dir = new File(resource.getFile()); + File[] files = dir.listFiles(new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.endsWith("jar"); + } + }); + + if (files == null) { + return new String[0]; + } + + String[] jars = new String[files.length]; + + for (int i = 0; i < files.length; i++) { + String path = files[i].getAbsolutePath(); + jars[i] = path.substring(path.indexOf("WEB-INF")); + } + return jars; + } + + /** + * Overloaded to handle specific problem with getting resources on the IBM WebSphere platform. + *

+ * WebSphere can not load resources if the resource to load is a folder name, such as a + * package name, you have to explicit name a resource that is a file. + * + * @param packageName the package name for the package to load + * @return URL's for the given package + * @throws IOException thrown if I/O error occur + */ + @Override + protected Enumeration getResources(String packageName) throws IOException { + + ClassLoader loader = getClassLoader(); + Vector v = new Vector(); + Enumeration enm = loader.getResources(packageName); + + while (enm.hasMoreElements()) { + URL url = (URL) enm.nextElement(); + v.add(url); + } + + // adding jars i.e. "WEB-INF/lib/my-lib.jar" + for (String path : getResourcePaths()) { + enm = loader.getResources(path); + if (enm.hasMoreElements()) { + v.add(enm.nextElement()); + } + } + return v.elements(); + } +} Index: stripes/src/net/sourceforge/stripes/util/ResolverUtil.java =================================================================== --- stripes/src/net/sourceforge/stripes/util/ResolverUtil.java (revision 1119) +++ stripes/src/net/sourceforge/stripes/util/ResolverUtil.java (working copy) @@ -125,6 +125,21 @@ private ClassLoader classloader; /** + * Default constructor. + */ + public ResolverUtil() { + } + + /** + * Extended constructor. + * + * @param classLoader the class loader to resolve classes from + */ + public ResolverUtil(ClassLoader classLoader) { + this.classloader = classLoader; + } + + /** * Provides access to the classes discovered so far. If no calls have been made to * any of the {@code find()} methods, this set will be empty. * @@ -202,11 +217,10 @@ */ public ResolverUtil find(Test test, String packageName) { packageName = packageName.replace('.', '/'); - ClassLoader loader = getClassLoader(); Enumeration urls; try { - urls = loader.getResources(packageName); + urls = getResources(packageName); } catch (IOException ioe) { log.warn("Could not read package: " + packageName, ioe); @@ -240,7 +254,17 @@ return this; } - + /** + * Method to retrieve resources from the class loader. + * + * @param packageName the name of the package from where to get resources. + * @return enumeration with {@code URL}s to found resources + * @throws IOException thrown if I/O error occur + */ + protected Enumeration getResources(String packageName) throws IOException { + return getClassLoader().getResources(packageName); + } + /** * Finds matches in a physical directory on a filesystem. Examines all * files within a directory - if the File object is not a directory, and ends with .class