001    /**
002     *
003     *  Licensed to the Apache Software Foundation (ASF) under one or more
004     *  contributor license agreements.  See the NOTICE file distributed with
005     *  this work for additional information regarding copyright ownership.
006     *  The ASF licenses this file to You under the Apache License, Version 2.0
007     *  (the "License"); you may not use this file except in compliance with
008     *  the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    
019    package org.apache.geronimo.jetty;
020    
021    import java.io.IOException;
022    import java.net.MalformedURLException;
023    import java.net.URL;
024    import java.security.PermissionCollection;
025    import java.util.Collection;
026    import java.util.EventListener;
027    import java.util.HashMap;
028    import java.util.HashSet;
029    import java.util.Hashtable;
030    import java.util.Iterator;
031    import java.util.Map;
032    import java.util.Set;
033    
034    import javax.management.MalformedObjectNameException;
035    import javax.management.ObjectName;
036    import javax.naming.Context;
037    import javax.transaction.TransactionManager;
038    
039    import org.apache.commons.logging.Log;
040    import org.apache.commons.logging.LogFactory;
041    import org.apache.geronimo.connector.outbound.connectiontracking.TrackedConnectionAssociator;
042    import org.apache.geronimo.gbean.GBeanInfo;
043    import org.apache.geronimo.gbean.GBeanInfoBuilder;
044    import org.apache.geronimo.gbean.GBeanLifecycle;
045    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
046    import org.apache.geronimo.j2ee.management.impl.InvalidObjectNameException;
047    import org.apache.geronimo.jetty.interceptor.BeforeAfter;
048    import org.apache.geronimo.jetty.interceptor.ComponentContextBeforeAfter;
049    import org.apache.geronimo.jetty.interceptor.InstanceContextBeforeAfter;
050    import org.apache.geronimo.jetty.interceptor.SecurityContextBeforeAfter;
051    import org.apache.geronimo.jetty.interceptor.ThreadClassloaderBeforeAfter;
052    import org.apache.geronimo.jetty.interceptor.WebApplicationContextBeforeAfter;
053    import org.apache.geronimo.kernel.Kernel;
054    import org.apache.geronimo.kernel.ObjectNameUtil;
055    import org.apache.geronimo.management.J2EEApplication;
056    import org.apache.geronimo.management.J2EEServer;
057    import org.apache.geronimo.management.geronimo.WebConnector;
058    import org.apache.geronimo.management.geronimo.WebContainer;
059    import org.apache.geronimo.management.geronimo.WebModule;
060    import org.apache.geronimo.naming.enc.EnterpriseNamingContext;
061    import org.apache.geronimo.security.deploy.DefaultPrincipal;
062    import org.apache.geronimo.transaction.GeronimoUserTransaction;
063    import org.mortbay.http.Authenticator;
064    import org.mortbay.http.HttpException;
065    import org.mortbay.http.HttpRequest;
066    import org.mortbay.http.HttpResponse;
067    import org.mortbay.jetty.servlet.AbstractSessionManager;
068    import org.mortbay.jetty.servlet.Dispatcher;
069    import org.mortbay.jetty.servlet.FilterHolder;
070    import org.mortbay.jetty.servlet.JSR154Filter;
071    import org.mortbay.jetty.servlet.ServletHolder;
072    import org.mortbay.jetty.servlet.ServletHttpRequest;
073    import org.mortbay.jetty.servlet.ServletHttpResponse;
074    import org.mortbay.jetty.servlet.WebApplicationContext;
075    import org.mortbay.jetty.servlet.WebApplicationHandler;
076    
077    /**
078     * Wrapper for a WebApplicationContext that sets up its J2EE environment.
079     *
080     * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
081     */
082    public class JettyWebAppContext extends WebApplicationContext implements GBeanLifecycle, JettyServletRegistration, WebModule {
083        private static Log log = LogFactory.getLog(JettyWebAppContext.class);
084    
085        private final String originalSpecDD;
086        private final J2EEServer server;
087        private final J2EEApplication application;
088    
089        private final ClassLoader webClassLoader;
090        private final JettyContainer jettyContainer;
091    
092        private final String webAppRoot;
093        private final URL configurationBaseURL;
094        private final WebApplicationHandler handler;
095        private final HandleInterceptor handleInterceptor;
096        private String displayName;
097        private final String[] welcomeFiles;
098    
099        private final BeforeAfter chain;
100        private final int contextLength;
101        private final SecurityContextBeforeAfter securityInterceptor;
102    
103        private final String objectName;
104    
105        private final Set servletNames = new HashSet();
106    
107        /**
108         * @deprecated never use this... this is only here because Jetty WebApplicationContext is externalizable
109         */
110        public JettyWebAppContext() {
111            server = null;
112            application = null;
113            originalSpecDD = null;
114            webClassLoader = null;
115            jettyContainer = null;
116            webAppRoot = null;
117            handler = null;
118            handleInterceptor = null; 
119            chain = null;
120            contextLength = 0;
121            securityInterceptor = null;
122            welcomeFiles = null;
123            objectName = null;
124            configurationBaseURL = null;
125        }
126    
127        public JettyWebAppContext(String objectName,
128                                  String originalSpecDD,
129                                  Map componentContext,
130                                  ClassLoader classLoader,
131                                  URL configurationBaseUrl,
132                                  Set unshareableResources,
133                                  Set applicationManagedSecurityResources,
134                String displayName,
135                Map contextParamMap,
136                Collection listenerClassNames,
137                boolean distributable,
138                Map mimeMap,
139                String[] welcomeFiles,
140                Map localeEncodingMapping,
141                Map errorPages,
142                Authenticator authenticator,
143                String realmName,
144                Map tagLibMap,
145                int sessionTimeoutSeconds,
146                                  WebApplicationHandlerFactory handlerFactory,
147                                  HandleInterceptor handleInterceptor,
148    
149                String policyContextID,
150                String securityRealmName,
151                DefaultPrincipal defaultPrincipal,
152                PermissionCollection checkedPermissions,
153                PermissionCollection excludedPermissions,
154    
155                Host host,
156                TransactionManager transactionManager,
157                TrackedConnectionAssociator trackedConnectionAssociator,
158                JettyContainer jettyContainer,
159                J2EEServer server,
160                J2EEApplication application,
161                Kernel kernel) throws Exception, IllegalAccessException, InstantiationException, ClassNotFoundException {
162    
163            assert componentContext != null;
164            assert classLoader != null;
165            assert configurationBaseUrl != null;
166            assert transactionManager != null;
167            assert trackedConnectionAssociator != null;
168            assert jettyContainer != null;
169    
170            this.server = server;
171            this.application = application;
172            this.objectName = objectName;
173            if (objectName != null) {
174                ObjectName myObjectName = ObjectNameUtil.getObjectName(objectName);
175                verifyObjectName(myObjectName);
176            }
177            this.configurationBaseURL = configurationBaseUrl;
178            this.jettyContainer = jettyContainer;
179            this.originalSpecDD = originalSpecDD;
180            this.handleInterceptor = handleInterceptor;
181            
182            setConfigurationClassNames(new String[]{});
183    
184            webAppRoot = configurationBaseUrl.toString();
185            this.webClassLoader = classLoader;
186            setClassLoader(this.webClassLoader);
187    
188            if (host != null) {
189                setHosts(host.getHosts());
190                setVirtualHosts(host.getVirtualHosts());
191            }
192    
193            handler = handlerFactory.createHandler();
194            addHandler(handler);
195    
196            //stuff from spec dd
197            setDisplayName(displayName);
198            setContextParamMap(contextParamMap);
199            setListenerClassNames(listenerClassNames);
200            setDistributable(distributable);
201            setMimeMap(mimeMap);
202            this.welcomeFiles = welcomeFiles;
203            setLocaleEncodingMapping(localeEncodingMapping);
204            setErrorPages(errorPages);
205            setAuthenticator(authenticator);
206            setRealmName(realmName);
207            setTagLibMap(tagLibMap);
208    
209            if (false == distributable) {
210                setSessionTimeoutSeconds(sessionTimeoutSeconds);
211            }
212    
213            GeronimoUserTransaction userTransaction = new GeronimoUserTransaction(transactionManager);
214            Context enc = EnterpriseNamingContext.createEnterpriseNamingContext(componentContext, userTransaction, kernel, webClassLoader);
215    
216            int index = 0;
217            BeforeAfter interceptor = new InstanceContextBeforeAfter(null, index++, unshareableResources, applicationManagedSecurityResources, trackedConnectionAssociator);
218            interceptor = new ComponentContextBeforeAfter(interceptor, index++, enc);
219            interceptor = new ThreadClassloaderBeforeAfter(interceptor, index++, index++, this.webClassLoader);
220            interceptor = new WebApplicationContextBeforeAfter(interceptor, index++, this);
221    //JACC
222    
223            if (securityRealmName != null) {
224                InternalJAASJettyRealm internalJAASJettyRealm = jettyContainer.addRealm(securityRealmName);
225                //wrap jetty realm with something that knows the dumb realmName
226                JAASJettyRealm realm = new JAASJettyRealm(realmName, internalJAASJettyRealm);
227                setRealm(realm);
228                this.securityInterceptor = new SecurityContextBeforeAfter(interceptor, index++, index++, policyContextID, defaultPrincipal, authenticator, checkedPermissions, excludedPermissions, realm, classLoader);
229                interceptor = this.securityInterceptor;
230            } else {
231                securityInterceptor = null;
232            }
233    //      end JACC
234            chain = interceptor;
235            contextLength = index;
236    
237            //cheat -- add jsr154 filter not as a gbean
238            FilterHolder jsr154FilterHolder = new FilterHolder(handler, "jsr154", JSR154Filter.class.getName());
239            handler.addFilterHolder(jsr154FilterHolder);
240            jsr154FilterHolder.setInitParameter("unwrappedDispatch", "true");
241            handler.addFilterPathMapping("/*", "jsr154", Dispatcher.__REQUEST | Dispatcher.__FORWARD | Dispatcher.__INCLUDE | Dispatcher.__ERROR);
242        }
243    
244    
245        public String getObjectName() {
246            return objectName;
247        }
248    
249        public boolean isStateManageable() {
250            return true;
251        }
252    
253        public boolean isStatisticsProvider() {
254            return false;
255        }
256    
257        public boolean isEventProvider() {
258            return true;
259        }
260    
261        public URL getWARDirectory() {
262            return configurationBaseURL;
263        }
264    
265        public String getWARName() {
266            //todo: make this return something more consistent
267            try {
268                return ObjectName.getInstance(objectName).getKeyProperty(NameFactory.J2EE_NAME);
269            } catch (MalformedObjectNameException e) {
270                return null;
271            }
272        }
273    
274        public WebContainer getContainer() {
275            return jettyContainer;
276        }
277    
278        public URL getURLFor() {
279            WebConnector[] connectors = (WebConnector[]) jettyContainer.getConnectors();
280            Map map = new HashMap();
281            for (int i = 0; i < connectors.length; i++) {
282                WebConnector connector = connectors[i];
283                map.put(connector.getProtocol(), connector.getConnectUrl());
284            }
285            String urlPrefix;
286            if((urlPrefix = (String) map.get("HTTP")) == null) {
287                if((urlPrefix = (String) map.get("HTTPS")) == null) {
288                    urlPrefix = (String) map.get("AJP");
289                }
290            }
291            if(urlPrefix == null) {
292                return null;
293            }
294            try {
295                return new URL(urlPrefix + getContextPath());
296            } catch (MalformedURLException e) {
297                log.error("Bad URL to connect to web app", e);
298                return null;
299            }
300        }
301    
302        public Object enterContextScope(HttpRequest httpRequest, HttpResponse httpResponse) {
303            Object[] context = new Object[contextLength];
304            chain.before(context, httpRequest, httpResponse);
305            return context;
306        }
307    
308        public void leaveContextScope(HttpRequest httpRequest, HttpResponse httpResponse, Object oldScope) {
309            Object[] context = (Object[]) oldScope;
310            chain.after(context, httpRequest, httpResponse);
311        }
312    
313        public void handle(HttpRequest httpRequest, HttpResponse httpResponse) throws HttpException, IOException {
314            super.handle(httpRequest, httpResponse);
315        }
316        
317        public void handle(String pathInContext, String pathParams, HttpRequest httpRequest, HttpResponse httpResponse)
318                throws HttpException, IOException {
319            ServletHttpRequest request = (ServletHttpRequest) httpRequest.getWrapper();
320            if (null == request) {
321                request = new GeronimoServletHttpRequest(handler, null, httpRequest);
322                ServletHttpResponse response = new ServletHttpResponse(request, httpResponse);
323                httpRequest.setWrapper(request);
324                httpResponse.setWrapper(response);
325            }
326            ((GeronimoServletHttpRequest) request).setRequestedSessionId(pathParams);
327            if (null != handleInterceptor) {
328                handleInterceptor.handle(pathInContext, pathParams, httpRequest, httpResponse, new EndHandleInterceptor());   
329            } else {
330                super.handle(pathInContext, pathParams, httpRequest, httpResponse);
331            }
332        }
333        
334        public ClassLoader getWebClassLoader() {
335            return webClassLoader;
336        }
337    
338        public void doStart() throws Exception {
339            // reset the classsloader... jetty likes to set it to null when stopping
340            setClassLoader(webClassLoader);
341    
342            // merge Geronimo and Jetty Lifecycles
343            if (!isStarting()) {
344                super.start();
345                return;
346            }
347    
348            ((AbstractSessionManager) getServletHandler().getSessionManager()).setUseRequestedId(true);
349    
350            setWAR(webAppRoot);
351    
352            jettyContainer.addContext(this);
353    
354            Object context = enterContextScope(null, null);
355            try {
356                super.doStart();
357            } finally {
358                leaveContextScope(null, null, context);
359            }
360            //super.doStart sets welcomefiles to null!!
361            setWelcomeFiles(welcomeFiles);
362    
363            log.debug("JettyWebAppContext started");
364        }
365    
366        public void doStop() throws Exception {
367            // merge Geronimo and Jetty Lifecycles
368            if (!isStopping()) {
369                super.stop();
370                return;
371            }
372    
373            if (securityInterceptor != null) {
374                securityInterceptor.stop(jettyContainer);
375            }
376            Object context = enterContextScope(null, null);
377            try {
378                super.doStop();
379            } finally {
380                leaveContextScope(null, null, context);
381                jettyContainer.removeContext(this);
382            }
383    
384            // No more logging will occur for this ClassLoader. Inform the LogFactory to avoid a memory leak.
385            LogFactory.release(webClassLoader);
386    
387            log.debug("JettyWebAppContext stopped");
388        }
389    
390        public void doFail() {
391            try {
392                //this will call doStop
393                super.stop();
394            } catch (InterruptedException e) {
395            }
396    
397            log.warn("JettyWebAppContext failed");
398        }
399    
400        //pass through attributes.  They should be constructor params
401    
402        //TODO encourage jetty to improve their naming convention.
403        public void setContextParamMap(Map initParameters) {
404            if (initParameters != null) {
405                for (Iterator iterator = initParameters.entrySet().iterator(); iterator.hasNext();) {
406                    Map.Entry entry = (Map.Entry) iterator.next();
407                    setInitParameter((String) entry.getKey(), (String) entry.getValue());
408                }
409            }
410        }
411    
412        public void setLocaleEncodingMapping(Map localeEncodingMap) {
413            if (localeEncodingMap != null) {
414                for (Iterator iterator = localeEncodingMap.entrySet().iterator(); iterator.hasNext();) {
415                    Map.Entry entry = (Map.Entry) iterator.next();
416                    addLocaleEncoding((String) entry.getKey(), (String) entry.getValue());
417                }
418            }
419        }
420    
421        public void setListenerClassNames(Collection eventListeners) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
422            if (eventListeners != null) {
423                for (Iterator iterator = eventListeners.iterator(); iterator.hasNext();) {
424                    String listenerClassName = (String) iterator.next();
425                    Class clazz = loadClass(listenerClassName);
426                    EventListener listener = (EventListener) clazz.newInstance();
427                    addEventListener(listener);
428                    handler.addEventListener(listener);
429                }
430            }
431        }
432    
433        public void setErrorPages(Map errorPageMap) {
434            if (errorPageMap != null) {
435                for (Iterator iterator = errorPageMap.entrySet().iterator(); iterator.hasNext();) {
436                    Map.Entry entry = (Map.Entry) iterator.next();
437                    setErrorPage((String) entry.getKey(), (String) entry.getValue());
438                }
439            }
440        }
441    
442        public void setTagLibMap(Map tagLibMap) {
443            if (tagLibMap != null) {
444                for (Iterator iterator = tagLibMap.entrySet().iterator(); iterator.hasNext();) {
445                    Map.Entry entry = (Map.Entry) iterator.next();
446                    setResourceAlias((String) entry.getKey(), (String) entry.getValue());
447                }
448            }
449        }
450    
451        public void setSessionTimeoutSeconds(int seconds) {
452            handler.setSessionInactiveInterval(seconds);
453        }
454    
455    
456        //TODO this is really dumb, but jetty likes to set the displayname to null frequently.
457        public String getDisplayName() {
458            return displayName;
459        }
460    
461        public void setDisplayName(String displayName) {
462            this.displayName = displayName;
463            super.setDisplayName(displayName);
464        }
465    
466        public String getDeploymentDescriptor() {
467            return originalSpecDD;
468        }
469    
470        public String getServer() {
471            return server.getObjectName();
472        }
473    
474        public String getApplication() {
475            if (application == null) {
476                return null;
477            }
478            return application.getObjectName();
479        }
480    
481        public String[] getJavaVMs() {
482            return server.getJavaVMs();
483        }
484    
485        public String[] getServlets() {
486            synchronized(servletNames) {
487                return (String[]) servletNames.toArray(new String[servletNames.size()]);
488            }
489        }
490    
491        /**
492         * ObjectName must match this pattern:
493         * <p/>
494         * domain:j2eeType=WebModule,name=MyName,J2EEServer=MyServer,J2EEApplication=MyApplication
495         */
496        private void verifyObjectName(ObjectName objectName) {
497            if (objectName.isPattern()) {
498                throw new InvalidObjectNameException("ObjectName can not be a pattern", objectName);
499            }
500            Hashtable keyPropertyList = objectName.getKeyPropertyList();
501            if (!NameFactory.WEB_MODULE.equals(keyPropertyList.get("j2eeType"))) {
502                throw new InvalidObjectNameException("WebModule object name j2eeType property must be 'WebModule'", objectName);
503            }
504            if (!keyPropertyList.containsKey(NameFactory.J2EE_NAME)) {
505                throw new InvalidObjectNameException("WebModule object must contain a name property", objectName);
506            }
507            if (!keyPropertyList.containsKey(NameFactory.J2EE_SERVER)) {
508                throw new InvalidObjectNameException("WebModule object name must contain a J2EEServer property", objectName);
509            }
510            if (!keyPropertyList.containsKey(NameFactory.J2EE_APPLICATION)) {
511                throw new InvalidObjectNameException("WebModule object name must contain a J2EEApplication property", objectName);
512            }
513            if (keyPropertyList.size() != 4) {
514                throw new InvalidObjectNameException("WebModule object name can only have j2eeType, name, J2EEApplication, and J2EEServer properties", objectName);
515            }
516        }
517    
518        public void registerServletHolder(ServletHolder servletHolder, String servletName, Set servletMappings, String objectName) throws Exception {
519            //TODO filters
520            handler.addServletHolder(servletHolder);
521            if (servletMappings != null) {
522                for (Iterator iterator = servletMappings.iterator(); iterator.hasNext();) {
523                    String urlPattern = (String) iterator.next();
524                    handler.mapPathToServlet(urlPattern, servletName);
525                }
526            }
527            Object context = enterContextScope(null, null);
528            try {
529                servletHolder.start();
530            } finally {
531                leaveContextScope(null, null, context);
532            }
533            if (objectName != null) {
534                synchronized(servletNames) {
535                    servletNames.add(objectName);
536                }
537            }
538        }
539    
540        public boolean checkSecurityConstraints(String pathInContext, HttpRequest request, HttpResponse response) throws HttpException, IOException {
541            if (securityInterceptor != null) {
542                return securityInterceptor.checkSecurityConstraints(pathInContext, request, response);
543            }
544            return super.checkSecurityConstraints(pathInContext, request, response);
545        }
546    
547        private void doHandle(String pathInContext, String pathParams, HttpRequest httpRequest, HttpResponse httpResponse)
548                throws HttpException, IOException {
549            super.handle(pathInContext, pathParams, httpRequest, httpResponse);
550        }
551        
552        private class EndHandleInterceptor implements HandleInterceptor {
553    
554            public void handle(String pathInContext, String pathParams, HttpRequest httpRequest, HttpResponse httpResponse,
555                    HandleInterceptor end) throws HttpException, IOException {
556                doHandle(pathInContext, pathParams, httpRequest, httpResponse);
557            }
558        }
559        
560        public static final GBeanInfo GBEAN_INFO;
561        
562        public static final String GBEAN_ATTR_SESSION_TIMEOUT = "sessionTimeoutSeconds";
563        
564        public static final String GBEAN_REF_WEB_APPLICATION_HANDLER_FACTORY = "WebApplicationHandlerFactory";
565        public static final String GBEAN_REF_HANDLE_INTERCEPTOR = "HandleInterceptor";
566    
567        static {
568            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("Jetty WebApplication Context", JettyWebAppContext.class, NameFactory.WEB_MODULE);
569            infoBuilder.addAttribute("deploymentDescriptor", String.class, true);
570            //from jetty's webapp context
571    
572            infoBuilder.addAttribute("displayName", String.class, true);
573            infoBuilder.addAttribute("contextParamMap", Map.class, true);
574            infoBuilder.addAttribute("listenerClassNames", Collection.class, true);
575            infoBuilder.addAttribute("distributable", boolean.class, true);
576    
577            infoBuilder.addAttribute("mimeMap", Map.class, true);
578            infoBuilder.addAttribute("welcomeFiles", String[].class, true);
579            infoBuilder.addAttribute("localeEncodingMapping", Map.class, true);
580            infoBuilder.addAttribute("errorPages", Map.class, true);
581            infoBuilder.addAttribute("authenticator", Authenticator.class, true);
582            infoBuilder.addAttribute("realmName", String.class, true);
583            infoBuilder.addAttribute("tagLibMap", Map.class, true);
584            infoBuilder.addAttribute(GBEAN_ATTR_SESSION_TIMEOUT, int.class, true);
585            infoBuilder.addReference(GBEAN_REF_WEB_APPLICATION_HANDLER_FACTORY, WebApplicationHandlerFactory.class,
586                    NameFactory.GERONIMO_SERVICE);
587            infoBuilder.addReference(GBEAN_REF_HANDLE_INTERCEPTOR, HandleInterceptor.class, NameFactory.GERONIMO_SERVICE);
588            
589            infoBuilder.addAttribute("componentContext", Map.class, true);
590            infoBuilder.addAttribute("classLoader", ClassLoader.class, false);
591            infoBuilder.addAttribute("configurationBaseUrl", URL.class, true);
592            infoBuilder.addAttribute("unshareableResources", Set.class, true);
593            infoBuilder.addAttribute("applicationManagedSecurityResources", Set.class, true);
594    
595            infoBuilder.addAttribute("contextPath", String.class, true);
596    
597            infoBuilder.addReference("Host", Host.class, "Host");
598            infoBuilder.addReference("TransactionManager", TransactionManager.class, NameFactory.TRANSACTION_MANAGER);
599            infoBuilder.addReference("TrackedConnectionAssociator", TrackedConnectionAssociator.class, NameFactory.JCA_CONNECTION_TRACKER);
600            infoBuilder.addReference("JettyContainer", JettyContainer.class, NameFactory.GERONIMO_SERVICE);
601    
602            infoBuilder.addInterface(JettyServletRegistration.class);
603    
604            infoBuilder.addAttribute("policyContextID", String.class, true);
605            infoBuilder.addAttribute("securityRealmName", String.class, true);
606            infoBuilder.addAttribute("defaultPrincipal", DefaultPrincipal.class, true);
607    
608            infoBuilder.addAttribute("checkedPermissions", PermissionCollection.class, true);
609            infoBuilder.addAttribute("excludedPermissions", PermissionCollection.class, true);
610    
611            infoBuilder.addReference("J2EEServer", J2EEServer.class);
612            infoBuilder.addReference("J2EEApplication", J2EEApplication.class);
613    
614            infoBuilder.addAttribute("kernel", Kernel.class, false);
615            infoBuilder.addAttribute("objectName", String.class, false);
616            infoBuilder.addAttribute("server", String.class, false);
617            infoBuilder.addAttribute("application", String.class, false);
618            infoBuilder.addAttribute("javaVMs", String[].class, false);
619            infoBuilder.addAttribute("servlets", String[].class, false);
620    
621            infoBuilder.addInterface(WebModule.class);
622    
623            infoBuilder.setConstructor(new String[]{
624                    "objectName",
625                    "deploymentDescriptor",
626                    "componentContext",
627                    "classLoader",
628                    "configurationBaseUrl",
629                    "unshareableResources",
630                    "applicationManagedSecurityResources",
631    
632                    "displayName",
633                    "contextParamMap",
634                    "listenerClassNames",
635                    "distributable",
636                    "mimeMap",
637                    "welcomeFiles",
638                    "localeEncodingMapping",
639                    "errorPages",
640                    "authenticator",
641                    "realmName",
642                    "tagLibMap",
643                    GBEAN_ATTR_SESSION_TIMEOUT,
644                    GBEAN_REF_WEB_APPLICATION_HANDLER_FACTORY,
645                    GBEAN_REF_HANDLE_INTERCEPTOR,
646    
647                    "policyContextID",
648                    "securityRealmName",
649                    "defaultPrincipal",
650    
651                    "checkedPermissions",
652                    "excludedPermissions",
653    
654                    "Host",
655                    "TransactionManager",
656                    "TrackedConnectionAssociator",
657                    "JettyContainer",
658    
659                    "J2EEServer",
660                    "J2EEApplication",
661                    "kernel"
662            });
663    
664            GBEAN_INFO = infoBuilder.getBeanInfo();
665        }
666    
667        public static GBeanInfo getGBeanInfo() {
668            return GBEAN_INFO;
669        }
670    
671    }