Index: src/main/java/org/apache/shale/tiger/view/faces/LifecycleListener2.java
===================================================================
--- src/main/java/org/apache/shale/tiger/view/faces/LifecycleListener2.java	(Revision 450750)
+++ src/main/java/org/apache/shale/tiger/view/faces/LifecycleListener2.java	(Arbeitskopie)
@@ -117,6 +117,12 @@
 
 
     /**
+     * <p> Servlet context init parameter which defines which packages to scan for beans. </p>
+     */
+    public static final String SCAN_PACKAGES =
+            "org.apache.shale.tiger.SCAN_PACKAGES";
+
+    /**
      * <p>Application scope attribute under which a configured
      * {@link FacesConfigConfig} bean will be stored, containing
      * information parsed from the relevant <code>faces-config.xml</code>
@@ -210,11 +216,29 @@
             ; // Null means it is not initialized yet
         }
 
-        // Scan the classes in /WEB-INF/classes for interesting annotations
-        List<Class> classes = null;
+        List<Class> classes;
 
+        String scanPackages = servletContext.getInitParameter(SCAN_PACKAGES);
+        if (scanPackages != null) {
+            // Scan the classes configured by the scan_packages context parameter
+            try {
+                classes = packageClasses(servletContext, scanPackages);
+            } catch (ClassNotFoundException e) {
+                throw new FacesException(e);
+            } catch (IOException e) {
+                throw new FacesException(e);
+            }
+        }
+        else {
+            // Scan the classes in /WEB-INF/classes for interesting annotations
+            try {
+                classes = webClasses(servletContext);
+            } catch (ClassNotFoundException e) {
+                throw new FacesException(e);
+            }
+        }
+
         try {
-            classes = webClasses(servletContext);
             for (Class clazz : classes) {
                 if (application != null) {
                     registerClass(clazz, application);
@@ -227,24 +251,25 @@
             throw new FacesException(e);
         }
 
-        // Scan the classes in /WEB-INF/lib for interesting annotations
-        List<JarFile> archives = null;
-
-        try {
-            archives = webArchives(servletContext);
-            for (JarFile archive : archives) {
-                classes = archiveClasses(servletContext, archive);
-                for (Class clazz : classes) {
-                    if (application != null) {
-                        registerClass(clazz, application);
-                    } else {
-                        queueClass(clazz);
+        if (scanPackages == null) {
+            // Scan the classes in /WEB-INF/lib for interesting annotations
+            List<JarFile> archives = null;
+            try {
+                archives = webArchives(servletContext);
+                for (JarFile archive : archives) {
+                    classes = archiveClasses(servletContext, archive);
+                    for (Class clazz : classes) {
+                        if (application != null) {
+                            registerClass(clazz, application);
+                        } else {
+                            queueClass(clazz);
+                        }
+                        scanClass(clazz, config);
                     }
-                    scanClass(clazz, config);
                 }
+            } catch (Exception e) {
+                throw new FacesException(e);
             }
-        } catch (Exception e) {
-            throw new FacesException(e);
         }
 
         // Create a parser instance used to parse faces-config.xml resources
@@ -294,7 +319,40 @@
 
     }
 
+    /**
+     * <p>Return a list of the classes defined within the given packages
+     * If there are no such classes, a zero-length list
+     * will be returned.</p>
+     *
+     * @param scanPackages the package configuration
+     *
+     * @exception ClassNotFoundException if a located class cannot be loaded
+     * @exception IOException if an input/output error occurs
+     */
+    private List<Class> packageClasses(ServletContext servletContext, String scanPackages) throws ClassNotFoundException, IOException {
+        List<Class> list = new ArrayList<Class>();
 
+        String[] scanPackageTokens =  scanPackages.split(",");
+        for (String scanPackageToken : scanPackageTokens)
+        {
+            if (scanPackageToken.toLowerCase().endsWith(".jar"))
+            {
+                URL jarResource = servletContext.getResource(WEB_LIB_PREFIX + scanPackageToken);
+                String jarURLString = "jar:" + jarResource.toString() + "!/";
+                URL url = new URL(jarURLString);
+                JarFile jarFile = ((JarURLConnection) url.openConnection()).getJarFile();
+
+                list.addAll(archiveClasses(servletContext, jarFile));
+            }
+            else
+            {
+                PackageInfo.getInstance().getClasses(list, scanPackageToken);
+            }
+        }
+        return list;
+    }
+
+
     /**
      * <p>Respond to a context destroyed event.  Clean up our allocated
      * application scope attributes.</p>
@@ -1111,7 +1169,7 @@
                 return map.get(annotation);
             }
 
-    
+
             // Construct and cache a new Map identifying the
             // methods of interest for these callbacks
             map = new HashMap<Class,Method>();
Index: src/main/java/org/apache/shale/tiger/view/faces/PackageInfo.java
===================================================================
--- src/main/java/org/apache/shale/tiger/view/faces/PackageInfo.java	(Revision 0)
+++ src/main/java/org/apache/shale/tiger/view/faces/PackageInfo.java	(Revision 0)
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * 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.apache.shale.tiger.view.faces;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * allows to get a recursive list of classes starting with a package name
+ */
+public final class PackageInfo {
+
+    /**
+     * <p>The <code>Log</code> instance we will be using.</p>
+     */
+    private transient Log log = null;
+
+    /**
+     * the singleton for this class
+     */
+    private final static PackageInfo INSTANCE = new PackageInfo();
+
+    private PackageInfo() {
+        super();
+    }
+
+    /**
+     * get instance to this class
+     */
+    public final static PackageInfo getInstance() {
+        return INSTANCE;
+    }
+
+    /**
+     * get list of classes for given package
+     *
+     * @throws ClassNotFoundException
+     */
+    public Class[] getClasses(final List<Class> classes, final String pckgname) throws ClassNotFoundException {
+        Enumeration resources;
+        ClassLoader cld;
+        String path;
+        try {
+
+            // convert the package name to a path
+            path = pckgname.replace('.', '/');
+
+            cld = Thread.currentThread().getContextClassLoader();
+            if (cld == null) {
+                throw new ClassNotFoundException("Can't get class loader.");
+            }
+
+            // find the entry points to the classpath
+            resources = cld.getResources(path);
+            if (resources == null || !resources.hasMoreElements()) {
+                throw new ClassNotFoundException("No resource for " + path);
+            }
+        }
+        catch (NullPointerException e) {
+            throw(ClassNotFoundException) new ClassNotFoundException(pckgname + " (" + pckgname
+                    + ") does not appear to be a valid package", e);
+        }
+        catch (IOException e) {
+            throw(ClassNotFoundException) new ClassNotFoundException(pckgname + " (" + pckgname
+                    + ") does not appear to be a valid package", e);
+        }
+
+        // iterate through all resources containing the package in question
+        while (resources.hasMoreElements()) {
+            URL resource = (URL) resources.nextElement();
+            URLConnection connection = null;
+            try {
+                connection = resource.openConnection();
+            } catch (IOException e) {
+                throw(ClassNotFoundException) new ClassNotFoundException(pckgname + " (" + pckgname
+                        + ") does not appear to be a valid package", e);
+            }
+
+            if (connection instanceof JarURLConnection) {
+                // iterate trhough all the entries in the jar
+                JarURLConnection juc = (JarURLConnection) connection;
+                JarFile jarFile = null;
+                try {
+                    jarFile = juc.getJarFile();
+                } catch (IOException e) {
+                    throw(ClassNotFoundException) new ClassNotFoundException(pckgname + " (" + pckgname
+                            + ") does not appear to be a valid package", e);
+                }
+                Enumeration<JarEntry> entries = jarFile.entries();
+                while (entries.hasMoreElements()) {
+                    JarEntry jarEntry = entries.nextElement();
+                    String entryName = jarEntry.getName();
+                    if (!entryName.startsWith(path)) {
+                        continue;
+                    }
+                    if (!entryName.toLowerCase().endsWith(".class")) {
+                        continue;
+                    }
+                    String className = filenameToClassname(entryName);
+                    loadClass(classes, cld, className);
+                }
+            } else {
+                // iterate trhough all the children starting with the package name
+                File file;
+                try {
+                    file = new File(connection.getURL().toURI());
+                } catch (URISyntaxException e) {
+                    log().warn("error loading directory " + connection, e);
+                    continue;
+                }
+
+                listFilesRecursive(classes, file, cld, pckgname);
+            }
+        }
+
+        if (classes.size() < 1) {
+            throw new ClassNotFoundException(pckgname
+                    + " does not appear to be a valid package");
+        }
+
+        Class[] resolvedClasses = new Class[classes.size()];
+        classes.toArray(resolvedClasses);
+
+        return resolvedClasses;
+    }
+
+    /**
+     * convert a filename to a classname
+     */
+    protected String filenameToClassname(String entryName) {
+        return entryName.substring(0, entryName.length() - 6).replace('/', '.');
+    }
+
+    /**
+     * load the class <code>className</code> using the classloader <code>cld</code> and add it to the
+     * list
+     */
+    protected void loadClass(List<Class> classes, ClassLoader cld, String className) {
+        try {
+            classes.add(cld.loadClass(className));
+        }
+        catch (NoClassDefFoundError e) {
+            log().warn("error loading class " + className, e);
+        } catch (ClassNotFoundException e) {
+            log().warn("error loading class " + className, e);
+        }
+    }
+
+    /**
+     * traverse a directory structure starting at <code>base</code>
+     */
+    protected void listFilesRecursive(final List<Class> classes, final File base, final ClassLoader cld, final String pckgname) {
+        base.listFiles(new FileFilter() {
+            public boolean accept(File file) {
+                if (file.isDirectory()) {
+                    listFilesRecursive(classes, file, cld, pckgname + "." + file.getName());
+                    return false;
+                }
+                if (!file.getName().toLowerCase().endsWith(".class")) {
+                    return false;
+                }
+
+                String className = filenameToClassname(pckgname + "." + file.getName());
+                loadClass(classes, cld, className);
+
+                return false;
+            }
+        });
+    }
+
+    /**
+     * <p>Return the <code>Log</code> instance to be used for this class,
+     * instantiating a new one if necessary.</p>
+     */
+    private Log log() {
+
+        if (log == null) {
+            log = LogFactory.getLog(LifecycleListener2.class);
+        }
+        return log;
+
+    }
+}

Eigenschaftsänderungen: src/main/java/org/apache/shale/tiger/view/faces/PackageInfo.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Author Id Revision HeadURL
Name: svn:eol-style
   + native

