001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.jetty6;
019    
020    import java.net.URL;
021    import java.util.ArrayList;
022    import java.util.Collection;
023    import java.util.EventListener;
024    import java.util.HashMap;
025    import java.util.HashSet;
026    import java.util.Hashtable;
027    import java.util.Map;
028    import java.util.Set;
029    
030    import javax.management.MalformedObjectNameException;
031    import javax.management.ObjectName;
032    import javax.naming.Context;
033    import javax.security.auth.Subject;
034    import javax.security.auth.login.LoginException;
035    import javax.transaction.TransactionManager;
036    
037    import org.apache.commons.logging.Log;
038    import org.apache.commons.logging.LogFactory;
039    import org.apache.geronimo.connector.outbound.connectiontracking.TrackedConnectionAssociator;
040    import org.apache.geronimo.gbean.GBeanInfo;
041    import org.apache.geronimo.gbean.GBeanInfoBuilder;
042    import org.apache.geronimo.gbean.GBeanLifecycle;
043    import org.apache.geronimo.j2ee.RuntimeCustomizer;
044    import org.apache.geronimo.j2ee.annotation.Holder;
045    import org.apache.geronimo.j2ee.annotation.LifecycleMethod;
046    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
047    import org.apache.geronimo.j2ee.management.impl.InvalidObjectNameException;
048    import org.apache.geronimo.jetty6.handler.AbstractImmutableHandler;
049    import org.apache.geronimo.jetty6.handler.ComponentContextHandler;
050    import org.apache.geronimo.jetty6.handler.InstanceContextHandler;
051    import org.apache.geronimo.jetty6.handler.JettySecurityHandler;
052    import org.apache.geronimo.jetty6.handler.LifecycleCommand;
053    import org.apache.geronimo.jetty6.handler.ThreadClassloaderHandler;
054    import org.apache.geronimo.jetty6.handler.TwistyWebAppContext;
055    import org.apache.geronimo.jetty6.handler.UserTransactionHandler;
056    import org.apache.geronimo.kernel.Kernel;
057    import org.apache.geronimo.kernel.ObjectNameUtil;
058    import org.apache.geronimo.management.J2EEApplication;
059    import org.apache.geronimo.management.J2EEServer;
060    import org.apache.geronimo.management.geronimo.WebContainer;
061    import org.apache.geronimo.management.geronimo.WebModule;
062    import org.apache.geronimo.naming.enc.EnterpriseNamingContext;
063    import org.apache.geronimo.security.jacc.RunAsSource;
064    import org.apache.geronimo.transaction.GeronimoUserTransaction;
065    import org.mortbay.jetty.Handler;
066    import org.mortbay.jetty.MimeTypes;
067    import org.mortbay.jetty.security.Authenticator;
068    import org.mortbay.jetty.servlet.ErrorPageErrorHandler;
069    import org.mortbay.jetty.servlet.ServletHandler;
070    import org.mortbay.jetty.servlet.ServletHolder;
071    import org.mortbay.jetty.servlet.ServletMapping;
072    import org.mortbay.jetty.servlet.SessionHandler;
073    
074    /**
075     * Wrapper for a WebApplicationContext that sets up its J2EE environment.
076     *
077     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
078     */
079    public class JettyWebAppContext implements GBeanLifecycle, JettyServletRegistration, WebModule {
080        private static Log log = LogFactory.getLog(JettyWebAppContext.class);
081    
082        private final String originalSpecDD;
083        private final J2EEServer server;
084        private final J2EEApplication application;
085    
086        private final ClassLoader webClassLoader;
087        private final JettyContainer jettyContainer;
088    
089        private final String webAppRoot;
090        private final URL configurationBaseURL;
091        private String displayName;
092    
093        private final String objectName;
094        private final TwistyWebAppContext webAppContext;//delegate
095        private final AbstractImmutableHandler lifecycleChain;
096        private final Context componentContext;
097        private final Holder holder;
098        private final RunAsSource runAsSource;
099    
100        private final Set<String> servletNames = new HashSet<String>();
101    
102        public JettyWebAppContext(String objectName,
103                String originalSpecDD,
104                Map<String, Object> componentContext,
105                ClassLoader classLoader,
106                URL configurationBaseUrl,
107                Set unshareableResources,
108                Set applicationManagedSecurityResources,
109                String displayName,
110                Map contextParamMap,
111                Collection<String> listenerClassNames,
112                boolean distributable,
113                Map mimeMap,
114                String[] welcomeFiles,
115                Map<String, String> localeEncodingMapping,
116                Map errorPages,
117                Authenticator authenticator,
118                String realmName,
119                Map<String, String> tagLibMap,
120                boolean compactPath,
121    
122                int sessionTimeoutSeconds,
123                SessionHandlerFactory handlerFactory,
124                PreHandlerFactory preHandlerFactory,
125    
126                String policyContextID,
127                String securityRealmName,
128    
129                RunAsSource runAsSource, Holder holder,
130    
131                Host host,
132                TransactionManager transactionManager,
133                TrackedConnectionAssociator trackedConnectionAssociator,
134                JettyContainer jettyContainer,
135                RuntimeCustomizer contextCustomizer,
136    
137                J2EEServer server,
138                J2EEApplication application,
139                Kernel kernel) throws Exception {
140    
141            assert componentContext != null;
142            assert classLoader != null;
143            assert configurationBaseUrl != null;
144            assert transactionManager != null;
145            assert trackedConnectionAssociator != null;
146            assert jettyContainer != null;
147    
148            this.holder = holder == null ? Holder.EMPTY : holder;
149    
150            this.runAsSource = runAsSource == null? RunAsSource.NULL: runAsSource;
151    
152            SessionHandler sessionHandler;
153            if (null != handlerFactory) {
154                if (null == preHandlerFactory) {
155                    throw new IllegalStateException("A preHandlerFactory must be set if an handler factory is set.");
156                }
157                PreHandler preHandler = preHandlerFactory.createHandler();
158                sessionHandler = handlerFactory.createHandler(preHandler);
159            } else {
160                sessionHandler = new SessionHandler();
161            }
162            JettySecurityHandler securityHandler = null;
163            if (securityRealmName != null) {
164                InternalJAASJettyRealm internalJAASJettyRealm = jettyContainer.addRealm(securityRealmName);
165                //wrap jetty realm with something that knows the dumb realmName
166                JAASJettyRealm realm = new JAASJettyRealm(realmName, internalJAASJettyRealm);
167                Subject defaultSubject =  this.runAsSource.getDefaultSubject();
168                securityHandler = new JettySecurityHandler(authenticator, realm, policyContextID, defaultSubject);
169            }
170    
171            ServletHandler servletHandler = new ServletHandler();
172    
173            webAppContext = new TwistyWebAppContext(securityHandler, sessionHandler, servletHandler, null);
174            //See Jetty-386.  Setting this to true can expose secured content.
175            webAppContext.setCompactPath(compactPath);
176    
177            //wrap the web app context with the jndi handler
178            GeronimoUserTransaction userTransaction = new GeronimoUserTransaction(transactionManager);
179            this.componentContext = EnterpriseNamingContext.createEnterpriseNamingContext(componentContext, userTransaction, kernel, classLoader);
180    
181            //install jasper injection support if required
182            if (contextCustomizer != null) {
183                Map<String, Object> servletContext = new HashMap<String, Object>();
184                Map<Class, Object> customizerContext = new HashMap<Class, Object>();
185                customizerContext.put(Map.class, servletContext);
186                customizerContext.put(Context.class, JettyWebAppContext.this.componentContext);
187                contextCustomizer.customize(customizerContext);
188                for (Map.Entry<String, Object> entry: servletContext.entrySet()) {
189                    webAppContext.setAttribute(entry.getKey(), entry.getValue());
190                }
191            }
192    
193            // localize access to next
194            {
195                //install the other handlers inside the web app context
196                Handler next = webAppContext.newTwistyHandler();
197                next = new ThreadClassloaderHandler(next, classLoader);
198    
199                next = new InstanceContextHandler(next, unshareableResources, applicationManagedSecurityResources, trackedConnectionAssociator);
200                next = new UserTransactionHandler(next, userTransaction);
201                next = new ComponentContextHandler(next, this.componentContext);
202                webAppContext.setTwistyHandler(next);
203    
204                lifecycleChain = (AbstractImmutableHandler) next;
205            }
206            MimeTypes mimeTypes = new MimeTypes();
207            mimeTypes.setMimeMap(mimeMap);
208            webAppContext.setMimeTypes(mimeTypes);
209    
210            this.server = server;
211            this.application = application;
212            this.objectName = objectName;
213            if (objectName != null) {
214                ObjectName myObjectName = ObjectNameUtil.getObjectName(objectName);
215                verifyObjectName(myObjectName);
216            }
217            this.configurationBaseURL = configurationBaseUrl;
218            this.jettyContainer = jettyContainer;
219            this.originalSpecDD = originalSpecDD;
220    
221            //DONT install the jetty TLD configuration as we find and create all the listeners ourselves
222            webAppContext.setConfigurationClasses(new String[]{});
223    
224            webAppRoot = configurationBaseUrl.toString();
225            webClassLoader = classLoader;
226            webAppContext.setClassLoader(webClassLoader);
227    
228            if (host != null) {
229                webAppContext.setConnectorNames(host.getHosts());
230                webAppContext.setVirtualHosts(host.getVirtualHosts());
231            }
232    
233            //stuff from spec dd
234            webAppContext.setDisplayName(displayName);
235            webAppContext.setInitParams(contextParamMap);
236            setListenerClassNames(listenerClassNames);
237            webAppContext.setDistributable(distributable);
238            webAppContext.setWelcomeFiles(welcomeFiles);
239            setLocaleEncodingMapping(localeEncodingMapping);
240            setErrorPages(errorPages);
241            setTagLibMap(tagLibMap);
242    
243            if (!distributable) {
244                setSessionTimeoutSeconds(sessionTimeoutSeconds);
245            }
246    
247        }
248    
249    
250        public String getObjectName() {
251            return objectName;
252        }
253    
254        public boolean isStateManageable() {
255            return true;
256        }
257    
258        public boolean isStatisticsProvider() {
259            return false;
260        }
261    
262        public boolean isEventProvider() {
263            return true;
264        }
265    
266        public URL getWARDirectory() {
267            return configurationBaseURL;
268        }
269    
270        public String getWARName() {
271            //todo: make this return something more consistent
272            try {
273                return ObjectName.getInstance(objectName).getKeyProperty(NameFactory.J2EE_NAME);
274            } catch (MalformedObjectNameException e) {
275                return null;
276            }
277        }
278    
279        public WebContainer getContainer() {
280            return jettyContainer;
281        }
282    
283        public void setContextPath(String path) {
284            if (path == null || !path.startsWith("/")) {
285                throw new IllegalArgumentException("context path must be non-null and start with '/', not " + path);
286            }
287            this.webAppContext.setContextPath(path);
288        }
289    
290        public String getContextPath() {
291            return this.webAppContext.getContextPath();
292        }
293    
294        public void setWorkDir(String workDir) {
295            if(workDir == null) {
296                return;
297            }
298            this.webAppContext.setTempDirectory(jettyContainer.resolveToJettyHome(workDir));
299        }
300        
301        public ClassLoader getWebClassLoader() {
302            return webClassLoader;
303        }
304    
305        public AbstractImmutableHandler getLifecycleChain() {
306            return lifecycleChain;
307        }
308    
309        public Subject getSubjectForRole(String role) throws LoginException {
310            return runAsSource.getSubjectForRole(role);
311        }
312    
313        public Object newInstance(String className) throws InstantiationException, IllegalAccessException {
314            if (className == null) {
315                throw new InstantiationException("no class loaded");
316            }
317            return holder.newInstance(className, webClassLoader, componentContext);
318        }
319    
320        public void destroyInstance(Object o) throws Exception {
321            Class clazz = o.getClass();
322            if (holder != null) {
323                Map<String, LifecycleMethod> preDestroy = holder.getPreDestroy();
324                if (preDestroy != null) {
325                    Holder.apply(o, clazz, preDestroy);
326                }
327            }
328        }
329    
330        public void doStart() throws Exception {
331            // reset the classsloader... jetty likes to set it to null when stopping
332            this.webAppContext.setClassLoader(webClassLoader);
333            this.webAppContext.setWar(webAppRoot);
334    
335            getLifecycleChain().lifecycleCommand(new StartCommand());
336        }
337    
338        public void doStop() throws Exception {
339            getLifecycleChain().lifecycleCommand(new StopCommand());
340    
341            // No more logging will occur for this ClassLoader. Inform the LogFactory to avoid a memory leak.
342            LogFactory.release(webClassLoader);
343    
344            // need to release the JSF factories. Otherwise, we'll leak ClassLoaders.
345            //should be done in a myfaces gbean
346    //        FactoryFinder.releaseFactories();
347    
348            log.debug("JettyWebAppContext stopped");
349        }
350    
351        public void doFail() {
352            try {
353                doStop();
354            } catch (Exception e) {
355                //ignore
356            }
357    
358            log.warn("JettyWebAppContext failed");
359        }
360    
361        public class StartCommand implements LifecycleCommand {
362    
363            public void lifecycleMethod() throws Exception {
364                //order seems backwards... .maybe container is calling start itself???
365                jettyContainer.addContext(webAppContext);
366                webAppContext.start();
367            }
368        }
369    
370        public class StopCommand implements LifecycleCommand {
371    
372            public void lifecycleMethod() throws Exception {
373                webAppContext.stop();
374                //TODO is this order correct?
375                for (EventListener listener : webAppContext.getEventListeners()) {
376                    destroyInstance(listener);
377                }
378                jettyContainer.removeContext(webAppContext);
379            }
380        }
381        //pass through attributes.  They should be constructor params
382    
383        public void setLocaleEncodingMapping(Map<String, String> localeEncodingMap) {
384            if (localeEncodingMap != null) {
385                for (Map.Entry<String, String> entry : localeEncodingMap.entrySet()) {
386                    this.webAppContext.addLocaleEncoding(entry.getKey(), entry.getValue());
387                }
388            }
389        }
390    
391        public void setListenerClassNames(Collection<String> eventListeners) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
392            if (eventListeners != null) {
393                Collection<EventListener> listeners = new ArrayList<EventListener>();
394                for (String listenerClassName : eventListeners) {
395                    EventListener listener = (EventListener) newInstance(listenerClassName);
396                    listeners.add(listener);
397                }
398                webAppContext.setEventListeners(listeners.toArray(new EventListener[listeners.size()]));
399            }
400        }
401    
402        public void setErrorPages(Map errorPageMap) {
403            if (errorPageMap != null) {
404                ((ErrorPageErrorHandler) this.webAppContext.getErrorHandler()).setErrorPages(errorPageMap);
405            }
406        }
407    
408        public void setTagLibMap(Map<String, String> tagLibMap) {
409            if (tagLibMap != null) {
410                for (Map.Entry<String, String> entry : tagLibMap.entrySet()) {
411                    this.webAppContext.setResourceAlias(entry.getKey(), entry.getValue());
412                }
413            }
414        }
415    
416        public void setSessionTimeoutSeconds(int seconds) {
417            this.webAppContext.getSessionHandler().getSessionManager().setMaxInactiveInterval(seconds);
418        }
419    
420    
421        //TODO this is really dumb, but jetty5 liked to set the displayname to null frequently.
422        //we need to re-check for jetty6
423        public String getDisplayName() {
424            return displayName;
425        }
426    
427        public void setDisplayName(String displayName) {
428            this.displayName = displayName;
429            this.webAppContext.setDisplayName(displayName);
430        }
431    
432        public String getDeploymentDescriptor() {
433            return originalSpecDD;
434        }
435    
436        public String getServer() {
437            return server.getObjectName();
438        }
439    
440        public String getApplication() {
441            if (application == null) {
442                return null;
443            }
444            return application.getObjectName();
445        }
446    
447        public String[] getJavaVMs() {
448            return server.getJavaVMs();
449        }
450    
451        public String[] getServlets() {
452            synchronized (servletNames) {
453                return servletNames.toArray(new String[servletNames.size()]);
454            }
455        }
456    
457        public ServletHandler getServletHandler() {
458            return this.webAppContext.getServletHandler();
459        }
460    
461        /**
462         * ObjectName must match this pattern:
463         * <p/>
464         * domain:j2eeType=WebModule,name=MyName,J2EEServer=MyServer,J2EEApplication=MyApplication
465         *
466         * @param objectName ObjectName to verify
467         */
468        private void verifyObjectName(ObjectName objectName) {
469            if (objectName.isPattern()) {
470                throw new InvalidObjectNameException("ObjectName can not be a pattern", objectName);
471            }
472            Hashtable keyPropertyList = objectName.getKeyPropertyList();
473            if (!NameFactory.WEB_MODULE.equals(keyPropertyList.get("j2eeType"))) {
474                throw new InvalidObjectNameException("WebModule object name j2eeType property must be 'WebModule'", objectName);
475            }
476            if (!keyPropertyList.containsKey(NameFactory.J2EE_NAME)) {
477                throw new InvalidObjectNameException("WebModule object must contain a name property", objectName);
478            }
479            if (!keyPropertyList.containsKey(NameFactory.J2EE_SERVER)) {
480                throw new InvalidObjectNameException("WebModule object name must contain a J2EEServer property", objectName);
481            }
482            if (!keyPropertyList.containsKey(NameFactory.J2EE_APPLICATION)) {
483                throw new InvalidObjectNameException("WebModule object name must contain a J2EEApplication property", objectName);
484            }
485            if (keyPropertyList.size() != 4) {
486                throw new InvalidObjectNameException("WebModule object name can only have j2eeType, name, J2EEApplication, and J2EEServer properties", objectName);
487            }
488        }
489    
490        public void registerServletHolder(ServletHolder servletHolder, String servletName, Set<String> servletMappings, String objectName) throws Exception {
491            webAppContext.getServletHandler().addServlet(servletHolder);
492            if (servletMappings != null) {
493                for (String urlPattern : servletMappings) {
494                    ServletMapping servletMapping = new ServletMapping();
495                    servletMapping.setPathSpec(urlPattern);
496                    servletMapping.setServletName(servletName);
497                    this.webAppContext.getServletHandler().addServletMapping(servletMapping);
498                }
499            }
500    //        LifecycleCommand lifecycleCommand = new LifecycleCommand.StartCommand(servletHolder);
501    //        lifecycleChain.lifecycleCommand(lifecycleCommand);
502            if (objectName != null) {
503                synchronized (servletNames) {
504                    servletNames.add(objectName);
505                }
506            }
507        }
508    
509        public void unregisterServletHolder(ServletHolder servletHolder, String servletName, Set<String> servletMappings, String objectName) throws Exception {
510            //no way to remove servlets
511    //        webAppContext.getServletHandler().removeServlet(servletHolder);
512    //        if (servletMappings != null) {
513    //            for (Iterator iterator = servletMappings.iterator(); iterator.hasNext();) {
514    //                String urlPattern = (String) iterator.next();
515    //                ServletMapping servletMapping = new ServletMapping();
516    //                servletMapping.setPathSpec(urlPattern);
517    //                servletMapping.setServletName(servletName);
518    //                webAppContext.getServletHandler().removeServletMapping(servletMapping);
519    //            }
520    //        }
521    //        LifecycleCommand lifecycleCommand = new LifecycleCommand.StopCommand(servletHolder);
522    //        lifecycleChain.lifecycleCommand(lifecycleCommand);
523            if (objectName != null) {
524                synchronized (servletNames) {
525                    servletNames.remove(objectName);
526                }
527            }
528        }
529    
530        public static final GBeanInfo GBEAN_INFO;
531    
532        public static final String GBEAN_ATTR_SESSION_TIMEOUT = "sessionTimeoutSeconds";
533    
534        public static final String GBEAN_REF_SESSION_HANDLER_FACTORY = "SessionHandlerFactory";
535        public static final String GBEAN_REF_PRE_HANDLER_FACTORY = "PreHandlerFactory";
536    
537        static {
538            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("Jetty WebApplication Context", JettyWebAppContext.class, NameFactory.WEB_MODULE);
539            infoBuilder.addAttribute("deploymentDescriptor", String.class, true);
540            //from jetty6's webapp context
541    
542            infoBuilder.addAttribute("displayName", String.class, true);
543            infoBuilder.addAttribute("contextParamMap", Map.class, true);
544            infoBuilder.addAttribute("listenerClassNames", Collection.class, true);
545            infoBuilder.addAttribute("distributable", boolean.class, true);
546    
547            infoBuilder.addAttribute("mimeMap", Map.class, true);
548            infoBuilder.addAttribute("welcomeFiles", String[].class, true);
549            infoBuilder.addAttribute("localeEncodingMapping", Map.class, true);
550            infoBuilder.addAttribute("errorPages", Map.class, true);
551            infoBuilder.addAttribute("authenticator", Authenticator.class, true);
552            infoBuilder.addAttribute("realmName", String.class, true);
553            infoBuilder.addAttribute("tagLibMap", Map.class, true);
554            infoBuilder.addAttribute(GBEAN_ATTR_SESSION_TIMEOUT, int.class, true);
555            infoBuilder.addReference(GBEAN_REF_SESSION_HANDLER_FACTORY, SessionHandlerFactory.class,
556                    NameFactory.GERONIMO_SERVICE);
557            infoBuilder.addReference(GBEAN_REF_PRE_HANDLER_FACTORY, PreHandlerFactory.class, NameFactory.GERONIMO_SERVICE);
558    
559            infoBuilder.addAttribute("componentContext", Map.class, true);
560            infoBuilder.addAttribute("classLoader", ClassLoader.class, false);
561            infoBuilder.addAttribute("configurationBaseUrl", URL.class, true);
562            infoBuilder.addAttribute("unshareableResources", Set.class, true);
563            infoBuilder.addAttribute("applicationManagedSecurityResources", Set.class, true);
564    
565            infoBuilder.addAttribute("contextPath", String.class, true);
566            infoBuilder.addAttribute("compactPath", boolean.class, true);
567    
568            infoBuilder.addAttribute("workDir", String.class, true);
569            infoBuilder.addReference("Host", Host.class, "Host");
570            infoBuilder.addReference("TransactionManager", TransactionManager.class, NameFactory.JTA_RESOURCE);
571            infoBuilder.addReference("TrackedConnectionAssociator", TrackedConnectionAssociator.class, NameFactory.JCA_CONNECTION_TRACKER);
572            infoBuilder.addReference("JettyContainer", JettyContainer.class, NameFactory.GERONIMO_SERVICE);
573            infoBuilder.addReference("ContextCustomizer", RuntimeCustomizer.class, NameFactory.GERONIMO_SERVICE);
574    
575            infoBuilder.addInterface(JettyServletRegistration.class);
576    
577            infoBuilder.addAttribute("policyContextID", String.class, true);
578            infoBuilder.addAttribute("securityRealmName", String.class, true);
579            infoBuilder.addReference("RunAsSource", RunAsSource.class, NameFactory.JACC_MANAGER);
580    
581            infoBuilder.addAttribute("holder", Holder.class, true);
582    
583            infoBuilder.addReference("J2EEServer", J2EEServer.class);
584            infoBuilder.addReference("J2EEApplication", J2EEApplication.class);
585    
586            infoBuilder.addAttribute("kernel", Kernel.class, false);
587            infoBuilder.addAttribute("objectName", String.class, false);
588            infoBuilder.addAttribute("application", String.class, false);
589            infoBuilder.addAttribute("javaVMs", String[].class, false);
590            infoBuilder.addAttribute("servlets", String[].class, false);
591    
592            infoBuilder.addInterface(WebModule.class);
593    
594            infoBuilder.setConstructor(new String[]{
595                    "objectName",
596                    "deploymentDescriptor",
597                    "componentContext",
598                    "classLoader",
599                    "configurationBaseUrl",
600                    "unshareableResources",
601                    "applicationManagedSecurityResources",
602    
603                    "displayName",
604                    "contextParamMap",
605                    "listenerClassNames",
606                    "distributable",
607                    "mimeMap",
608                    "welcomeFiles",
609                    "localeEncodingMapping",
610                    "errorPages",
611                    "authenticator",
612                    "realmName",
613                    "tagLibMap",
614                    "compactPath",
615                    GBEAN_ATTR_SESSION_TIMEOUT,
616                    GBEAN_REF_SESSION_HANDLER_FACTORY,
617                    GBEAN_REF_PRE_HANDLER_FACTORY,
618    
619                    "policyContextID",
620                    "securityRealmName",
621                    "RunAsSource",
622    
623                    "holder",
624    
625                    "Host",
626                    "TransactionManager",
627                    "TrackedConnectionAssociator",
628                    "JettyContainer",
629                    "ContextCustomizer",
630    
631                    "J2EEServer",
632                    "J2EEApplication",
633                    "kernel"
634            });
635    
636            GBEAN_INFO = infoBuilder.getBeanInfo();
637        }
638    
639        public static GBeanInfo getGBeanInfo() {
640            return GBEAN_INFO;
641        }
642    
643    }