001    package org.beanlet.web;
002    
003    import java.io.BufferedReader;
004    import java.io.InputStreamReader;
005    import java.lang.reflect.Constructor;
006    import java.lang.reflect.Modifier;
007    import java.net.URL;
008    import java.security.AccessController;
009    import java.security.PrivilegedActionException;
010    import java.security.PrivilegedExceptionAction;
011    import java.util.Enumeration;
012    import javax.servlet.ServletRequestEvent;
013    import javax.servlet.ServletRequestListener;
014    import org.beanlet.BeanletApplicationException;
015    
016    /**
017     * Add the following configuration to the web application's {@code web.xml} file
018     * to support the {@code Request} and {@code Session} beanlet scopes.
019     * </br>
020     * Not required for Servlet 3.0 containers.
021     * </br>
022     * <pre>
023     * &lt;web-app&gt;
024     *   ...
025     *   &lt;listener&gt;
026     *     &lt;listener-class&gt;org.beanlet.web.RequestContextListener&lt;listener-class&gt;
027     *   &lt;/listener&gt;
028     *   ...
029     * &lt;/web-app&gt;
030     * </pre>
031     * 
032     * @see Request
033     * @see Session
034     * @author Leon van Zantvoort
035     */
036    public class RequestContextListener implements ServletRequestListener {
037    
038        private static class LazyHolder {
039            static final Constructor<ServletRequestListener> delegate;
040            static {
041                try {
042                    try {
043                        Constructor constructor = AccessController.doPrivileged(
044                                new PrivilegedExceptionAction<Constructor>() {
045                            public Constructor run() throws Exception {
046                                String path = "META-INF/services/" + 
047                                        RequestContextListener.class.getName();
048    
049                                // PERMISSION: java.lang.RuntimePermission getClassLoader
050                                ClassLoader loader = Thread.currentThread().
051                                        getContextClassLoader();
052                                final Enumeration<URL> urls;
053                                if (loader == null) {
054                                    urls = RequestContextListener.class.
055                                            getClassLoader().getResources(path);
056                                } else {
057                                    urls = loader.getResources(path);
058                                }
059                                while (urls.hasMoreElements()) {
060                                    URL url = urls.nextElement();
061                                    BufferedReader reader = new BufferedReader(new InputStreamReader(
062                                            url.openStream()));
063                                    try {
064                                        String className = null;
065                                        while ((className = reader.readLine()) != null) {
066                                            final String name = className.trim();
067                                            if (!name.startsWith("#") && !name.startsWith(";") &&
068                                                    !name.startsWith("//")) {
069                                                final Class<?> cls;
070                                                if (loader == null) {
071                                                    cls = Class.forName(name);
072                                                } else {
073                                                    cls = Class.forName(name, true, loader);
074                                                }
075                                                int m = cls.getModifiers();
076                                                if (ServletRequestListener.class.isAssignableFrom(cls) &&
077                                                        !Modifier.isAbstract(m) &&
078                                                        !Modifier.isInterface(m)) {
079                                                    // PERMISSION: java.lang.RuntimePermission accessDeclaredMembers
080                                                    Constructor constructor = cls.getDeclaredConstructor();
081                                                    // PERMISSION: java.lang.reflect.ReflectPermission suppressAccessChecks
082                                                    if (!Modifier.isPublic(constructor.getModifiers())) {
083                                                        constructor.setAccessible(true);
084                                                    }
085                                                    return constructor;
086                                                } else {
087                                                    throw new ClassCastException(cls.getName());
088                                                }
089                                            }
090                                        }
091                                    } finally {
092                                        reader.close();
093                                    }
094                                }
095                                throw new BeanletApplicationException("No " +
096                                        "ServletRequestListener implementation " +
097                                        "found.");
098                            }
099                        });
100                        @SuppressWarnings("unchecked")
101                        Constructor<ServletRequestListener> tmp = 
102                                (Constructor<ServletRequestListener>) constructor;
103                        delegate = tmp;
104                    } catch (PrivilegedActionException e) {
105                        throw e.getException();
106                    }
107                } catch (BeanletApplicationException e) {
108                    throw e;
109                } catch (RuntimeException e) {
110                    throw new BeanletApplicationException(e);
111                } catch (Error e) {
112                    throw e;
113                } catch (Throwable t) {
114                    throw new BeanletApplicationException(t);
115                }
116            }
117        }
118    
119        private final ServletRequestListener delegate;
120        
121        public RequestContextListener() {
122            try {
123                try {
124                    delegate = LazyHolder.delegate.newInstance();
125                } catch (ExceptionInInitializerError e) {
126                    try {
127                        throw e.getException();
128                    } catch (Throwable t) {
129                        throw new BeanletApplicationException(t);
130                    }
131                }
132            } catch (BeanletApplicationException e) {
133                throw e;
134            } catch (RuntimeException e) {
135                throw e;
136            } catch (Error e) {
137                throw e;
138            } catch (Exception e) {
139                throw new BeanletApplicationException(e);
140            }
141        }
142        
143        public void requestInitialized(ServletRequestEvent event) {
144            delegate.requestInitialized(event);
145        }
146    
147        public void requestDestroyed(ServletRequestEvent event) {
148            delegate.requestDestroyed(event);
149        }
150    }