001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.web;
023:
024: import java.net.MalformedURLException;
025: import java.net.URL;
026: import java.net.URLClassLoader;
027: import java.security.Policy;
028: import java.util.ArrayList;
029: import java.util.HashSet;
030: import java.util.Iterator;
031: import java.util.Set;
032:
033: import javax.management.MBeanServer;
034: import javax.naming.Context;
035: import javax.naming.InitialContext;
036: import javax.naming.LinkRef;
037: import javax.naming.NamingException;
038: import javax.security.jacc.PolicyConfiguration;
039: import javax.security.jacc.PolicyConfigurationFactory;
040: import javax.security.jacc.PolicyContextException;
041:
042: import org.jboss.deployment.DeploymentException;
043: import org.jboss.deployment.DeploymentInfo;
044: import org.jboss.deployment.J2eeApplicationMetaData;
045: import org.jboss.ejb.Container;
046: import org.jboss.ejb.EjbUtil;
047: import org.jboss.logging.Logger;
048: import org.jboss.metadata.EjbLocalRefMetaData;
049: import org.jboss.metadata.EjbRefMetaData;
050: import org.jboss.metadata.EnvEntryMetaData;
051: import org.jboss.metadata.MessageDestinationMetaData;
052: import org.jboss.metadata.MessageDestinationRefMetaData;
053: import org.jboss.metadata.ResourceEnvRefMetaData;
054: import org.jboss.metadata.ResourceRefMetaData;
055: import org.jboss.metadata.WebMetaData;
056: import org.jboss.metadata.serviceref.ServiceRefDelegate;
057: import org.jboss.mx.loading.LoaderRepositoryFactory;
058: import org.jboss.util.naming.NonSerializableFactory;
059: import org.jboss.util.naming.Util;
060: import org.jboss.web.AbstractWebContainer.WebDescriptorParser;
061: import org.jboss.ws.integration.ServiceRefMetaData;
062: import org.jboss.ws.integration.URLLoaderAdapter;
063: import org.jboss.ws.integration.UnifiedVirtualFile;
064: import org.omg.CORBA.ORB;
065:
066: /** A template pattern class for web deployer integration into JBoss. This class
067: should be subclasses by war deployers providers wishing to integrate into
068: a JBoss server.
069:
070: It provides support for mapping the following web-app.xml/jboss-web.xml elements
071: into the JBoss server JNDI namespace:
072: - env-entry
073: - resource-ref
074: - resource-env-ref
075: - ejb-ref
076: - ejb-local-ref
077: - security-domain
078:
079: Subclasses need to implement the {@link #performDeploy(WebApplication, String,
080: WebDescriptorParser) performDeploy()}
081: and {@link #performUndeploy(String, WebApplication) performUndeploy()} methods to perform the
082: container specific steps and return the web application info required by the
083: AbstractWebContainer class.
084:
085: Integration with the JBossSX security framework is based on the establishment
086: of a java:comp/env/security context as described in the
087: {@link #linkSecurityDomain(String,Context) linkSecurityDomain } comments.
088: The security context provides access to the JBossSX security mgr interface
089: implementations for use by subclass request interceptors. A outline of the
090: steps for authenticating a user is:
091: <code>
092: // Get the username & password from the request context...
093: String username = f(request);
094: String password = f(request);
095: // Get the JBoss security manager from the ENC context
096: InitialContext iniCtx = new InitialContext();
097: SecurityManager securityMgr = (SecurityManager) iniCtx.lookup("java:comp/env/security/securityMgr");
098: SimplePrincipal principal = new SimplePrincipal(username);
099: if( securityMgr.isValid(principal, password) )
100: {
101: // Indicate the user is allowed access to the web content...
102:
103: // Propagate the user info to JBoss for any calls into made by the servlet
104: SecurityAssociation.setPrincipal(principal);
105: SecurityAssociation.setCredential(password.toCharArray());
106: }
107: else
108: {
109: // Deny access...
110: }
111: </code>
112:
113: An outline of the steps for authorizing the user is:
114: <code>
115: // Get the username & required roles from the request context...
116: String username = f(request);
117: String[] roles = f(request);
118: // Get the JBoss security manager from the ENC context
119: InitialContext iniCtx = new InitialContext();
120: RealmMapping securityMgr = (RealmMapping) iniCtx.lookup("java:comp/env/security/realmMapping");
121: SimplePrincipal principal = new SimplePrincipal(username);
122: Set requiredRoles = new HashSet(Arrays.asList(roles));
123: if( securityMgr.doesUserHaveRole(principal, requiredRoles) )
124: {
125: // Indicate the user has the required roles for the web content...
126: }
127: else
128: {
129: // Deny access...
130: }
131: </code>
132:
133: The one thing to be aware of is the relationship between the thread context
134: class loader and the JNDI ENC context. Any method that attempts to access
135: the JNDI ENC context must have the ClassLoader in the WebApplication returned
136: from the {@link #performDeploy(WebApplication, String, WebDescriptorParser) performDeploy} as its thread
137: context ClassLoader or else the lookup for java:comp/env will fail with a
138: name not found exception, or worse, it will receive some other web application
139: ENC context. If your adapting a web container that is trying be compatible with
140: both 1.1 and 1.2 Java VMs this is something you need to pay special attention
141: to. For example, I have seen problems a request interceptor that was handling
142: the authentication/authorization callouts in tomcat3.2.1 not having the same
143: thread context ClassLoader as was used to dispatch the http service request.
144:
145: @see #performDeploy(WebApplication webApp, String warUrl,
146: WebDescriptorParser webAppParser)
147: @see #performUndeploy(String, WebApplication)
148: @see #parseWebAppDescriptors(DeploymentInfo,ClassLoader, WebMetaData)
149: @see #linkSecurityDomain(String, Context)
150: @see org.jboss.security.RealmMapping;
151: @see org.jboss.security.SimplePrincipal;
152: @see org.jboss.security.SecurityAssociation;
153:
154: @jmx.mbean
155: name="jboss.web:service=WebServer"
156: extends="org.jboss.deployment.SubDeployerMBean"
157:
158: @author Scott.Stark@jboss.org
159: @version $Revision: 61864 $
160: */
161: public abstract class AbstractWebDeployer {
162: public static final String ERROR = "org.jboss.web.AbstractWebContainer.error";
163: protected Logger log;
164:
165: protected MBeanServer server;
166: /** The parent class loader first model flag */
167: protected boolean java2ClassLoadingCompliance = false;
168: /** A flag indicating if war archives should be unpacked */
169: protected boolean unpackWars = true;
170: /** If true, ejb-links that don't resolve don't cause an error (fallback to jndi-name) */
171: protected boolean lenientEjbLink = false;
172: /** The default security-domain name to use */
173: protected String defaultSecurityDomain;
174:
175: public AbstractWebDeployer() {
176: log = Logger.getLogger(getClass());
177: }
178:
179: public abstract void init(Object containerConfig) throws Exception;
180:
181: public MBeanServer getServer() {
182: return server;
183: }
184:
185: public void setServer(MBeanServer server) {
186: this .server = server;
187: }
188:
189: /** Get the flag indicating if the normal Java2 parent first class loading
190: * model should be used over the servlet 2.3 web container first model.
191: * @return true for parent first, false for the servlet 2.3 model
192: * @jmx.managed-attribute
193: */
194: public boolean getJava2ClassLoadingCompliance() {
195: return java2ClassLoadingCompliance;
196: }
197:
198: /** Set the flag indicating if the normal Java2 parent first class loading
199: * model should be used over the servlet 2.3 web container first model.
200: * @param flag true for parent first, false for the servlet 2.3 model
201: * @jmx.managed-attribute
202: */
203: public void setJava2ClassLoadingCompliance(boolean flag) {
204: java2ClassLoadingCompliance = flag;
205: }
206:
207: /** Set the flag indicating if war archives should be unpacked. This may
208: * need to be set to false as long extraction paths under deploy can
209: * show up as deployment failures on some platforms.
210: *
211: * @jmx.managed-attribute
212: * @return true is war archives should be unpacked
213: */
214: public boolean getUnpackWars() {
215: return unpackWars;
216: }
217:
218: /** Get the flag indicating if war archives should be unpacked. This may
219: * need to be set to false as long extraction paths under deploy can
220: * show up as deployment failures on some platforms.
221: *
222: * @jmx.managed-attribute
223: * @param flag , true is war archives should be unpacked
224: */
225: public void setUnpackWars(boolean flag) {
226: this .unpackWars = flag;
227: }
228:
229: /**
230: * Get the flag indicating if ejb-link errors should be ignored
231: * in favour of trying the jndi-name in jboss-web.xml
232: * @return a <code>boolean</code> value
233: *
234: * @jmx.managed-attribute
235: */
236: public boolean getLenientEjbLink() {
237: return lenientEjbLink;
238: }
239:
240: /**
241: * Set the flag indicating if ejb-link errors should be ignored
242: * in favour of trying the jndi-name in jboss-web.xml
243: * @jmx.managed-attribute
244: */
245: public void setLenientEjbLink(boolean flag) {
246: lenientEjbLink = flag;
247: }
248:
249: /** Get the default security domain implementation to use if a war
250: * does not declare a security-domain.
251: *
252: * @return jndi name of the security domain binding to use.
253: * @jmx.managed-attribute
254: */
255: public String getDefaultSecurityDomain() {
256: return defaultSecurityDomain;
257: }
258:
259: /** Set the default security domain implementation to use if a war
260: * does not declare a security-domain.
261: *
262: * @param defaultSecurityDomain - jndi name of the security domain binding
263: * to use.
264: * @jmx.managed-attribute
265: */
266: public void setDefaultSecurityDomain(String defaultSecurityDomain) {
267: this .defaultSecurityDomain = defaultSecurityDomain;
268: }
269:
270: /** A template pattern implementation of the deploy() method. This method
271: calls the {@link #performDeploy(WebApplication, String, WebDescriptorParser) performDeploy()} method to
272: perform the container specific deployment steps and registers the
273: returned WebApplication in the deployment map. The steps performed are:
274:
275: ClassLoader appClassLoader = thread.getContextClassLoader();
276: URLClassLoader warLoader = URLClassLoader.newInstance(empty, appClassLoader);
277: thread.setContextClassLoader(warLoader);
278: WebDescriptorParser webAppParser = ...;
279: WebMetaData metaData = di.metaData;
280: // Create JACC permissions, contextID, etc. ...
281: WebApplication warInfo = new WebApplication(metaData);
282: performDeploy(warInfo, warUrl, webAppParser);
283: deploymentMap.put(warUrl, warInfo);
284: thread.setContextClassLoader(appClassLoader);
285:
286: The subclass performDeploy() implementation needs to invoke
287: webAppParser.parseWebAppDescriptors(loader, warInfo) to have the JNDI
288: java:comp/env namespace setup before any web app component can access
289: this namespace.
290:
291: Also, an MBean for each servlet deployed should be created and its
292: JMX ObjectName placed into the DeploymentInfo.mbeans list so that the
293: JSR77 layer can create the approriate model view. The servlet MBean
294: needs to provide access to the min, max and total time in milliseconds.
295: Expose this information via MinServiceTime, MaxServiceTime and TotalServiceTime
296: attributes to integrate seemlessly with the JSR77 factory layer.
297:
298: @param di The deployment info that contains the context-root element value
299: from the J2EE application/module/web application.xml descriptor. This may
300: be null if war was is not being deployed as part of an enterprise application.
301: It also contains the URL of the web application war.
302: */
303: public synchronized WebApplication start(DeploymentInfo di)
304: throws DeploymentException {
305: Thread thread = Thread.currentThread();
306: ClassLoader appClassLoader = thread.getContextClassLoader();
307: WebApplication warInfo = null;
308: try {
309: // Create a classloader for the war to ensure a unique ENC
310: URL[] empty = {};
311: URLClassLoader warLoader = URLClassLoader.newInstance(
312: empty, di.ucl);
313: thread.setContextClassLoader(warLoader);
314: WebDescriptorParser webAppParser = new DescriptorParser(di);
315: String webContext = di.webContext;
316: if (webContext != null
317: && webContext.startsWith("/") == false)
318: webContext = "/" + webContext;
319:
320: // Get the war URL
321: URL warURL = di.localUrl != null ? di.localUrl : di.url;
322:
323: if (log.isDebugEnabled()) {
324: log.debug("webContext: " + webContext);
325: log.debug("warURL: " + warURL);
326: log.debug("webAppParser: " + webAppParser);
327: }
328:
329: // Get the web.xml and jboss-web.xml descriptor metadata
330: WebMetaData webMetaData = (WebMetaData) di.metaData;
331:
332: // inherit the security setup from jboss-app.xml
333: if (di.parent != null
334: && di.parent.metaData instanceof J2eeApplicationMetaData) {
335: J2eeApplicationMetaData appMetaData = (J2eeApplicationMetaData) di.parent.metaData;
336:
337: if (webMetaData.getSecurityDomain() == null)
338: webMetaData.setSecurityDomain(appMetaData
339: .getSecurityDomain());
340:
341: webMetaData.mergeSecurityRoles(appMetaData
342: .getSecurityRoles());
343: }
344:
345: // Register the permissions with the JACC layer
346: String contextID = di.shortName;
347: if (contextID == null)
348: contextID = di.shortName;
349: webMetaData.setJaccContextID(contextID);
350: PolicyConfigurationFactory pcFactory = PolicyConfigurationFactory
351: .getPolicyConfigurationFactory();
352: PolicyConfiguration pc = pcFactory.getPolicyConfiguration(
353: contextID, true);
354: createPermissions(webMetaData, pc);
355: // Link this to the parent PC
356: DeploymentInfo current = di;
357: while (current.parent != null)
358: current = current.parent;
359: PolicyConfiguration parentPC = (PolicyConfiguration) current.context
360: .get("javax.security.jacc.PolicyConfiguration");
361: if (parentPC != null && parentPC != pc)
362: parentPC.linkConfiguration(pc);
363:
364: // Commit the policy configuration
365: pc.commit();
366: // Allow the policy to incorporate the policy configs
367: Policy.getPolicy().refresh();
368:
369: warInfo = new WebApplication(webMetaData);
370: warInfo.setDeploymentInfo(di);
371: warInfo.setClassLoader(warLoader);
372: performDeploy(warInfo, warURL.toString(), webAppParser);
373: } catch (DeploymentException e) {
374: di.context.put(ERROR, e);
375: throw e;
376: } catch (Exception e) {
377: DeploymentException ex = new DeploymentException(
378: "Error during deploy", e);
379: di.context.put(ERROR, ex);
380: throw ex;
381: } finally {
382: thread.setContextClassLoader(appClassLoader);
383: }
384: return warInfo;
385: }
386:
387: /** This method is called by the deploy() method template and must be overriden by
388: subclasses to perform the web container specific deployment steps.
389: @param webApp The web application information context. This contains the
390: metadata such as the context-root element value from the J2EE
391: application/module/web application.xml descriptor and virtual-host.
392: @param warUrl The string for the URL of the web application war.
393: @param webAppParser The callback interface the web container should use to
394: setup the web app JNDI environment for use by the web app components. This
395: needs to be invoked after the web app class loader is known, but before
396: and web app components attempt to access the java:comp/env JNDI namespace.
397: */
398: protected abstract void performDeploy(WebApplication webApp,
399: String warUrl, WebDescriptorParser webAppParser)
400: throws Exception;
401:
402: /** A template pattern implementation of the undeploy() method. This method
403: calls the {@link #performUndeploy(String, WebApplication) performUndeploy()} method to
404: perform the container specific undeployment steps and unregisters the
405: the warUrl from the deployment map.
406: */
407: public synchronized void stop(DeploymentInfo di)
408: throws DeploymentException {
409: URL warURL = di.localUrl != null ? di.localUrl : di.url;
410: String warUrl = warURL.toString();
411: try {
412: WebApplication webApp = (WebApplication) di.context
413: .get(AbstractWebContainer.WEB_APP);
414: performUndeploy(warUrl, webApp);
415: // Unegister the permissions with the JACC layer
416: WebMetaData webMetaData = (WebMetaData) di.metaData;
417: String contextID = webMetaData.getJaccContextID();
418: PolicyConfigurationFactory pcFactory = PolicyConfigurationFactory
419: .getPolicyConfigurationFactory();
420: PolicyConfiguration pc = pcFactory.getPolicyConfiguration(
421: contextID, true);
422: pc.delete();
423: } catch (DeploymentException e) {
424: throw e;
425: } catch (Exception e) {
426: throw new DeploymentException("Error during deploy", e);
427: }
428: }
429:
430: /** Called as part of the undeploy() method template to ask the
431: subclass for perform the web container specific undeployment steps.
432: */
433: protected abstract void performUndeploy(String warUrl,
434: WebApplication webApp) throws Exception;
435:
436: /** This method is invoked from within subclass performDeploy() method
437: implementations when they invoke WebDescriptorParser.parseWebAppDescriptors().
438:
439: @param loader the ClassLoader for the web application. May not be null.
440: @param metaData the WebMetaData from the WebApplication object passed to
441: the performDeploy method.
442: */
443: protected void parseWebAppDescriptors(DeploymentInfo di,
444: ClassLoader loader, WebMetaData metaData) throws Exception {
445: log.debug("AbstractWebContainer.parseWebAppDescriptors, Begin");
446: InitialContext iniCtx = new InitialContext();
447: Context envCtx = null;
448: Thread currentThread = Thread.currentThread();
449: ClassLoader currentLoader = currentThread
450: .getContextClassLoader();
451: try {
452: // Create a java:comp/env environment unique for the web application
453: log.debug("Creating ENC using ClassLoader: " + loader);
454: ClassLoader parent = loader.getParent();
455: while (parent != null) {
456: log.debug(".." + parent);
457: parent = parent.getParent();
458: }
459: // TODO: Where does this ENC get tidied up?
460: currentThread.setContextClassLoader(loader);
461: metaData.setENCLoader(loader);
462: envCtx = (Context) iniCtx.lookup("java:comp");
463:
464: ORB orb = null;
465: try {
466: orb = (ORB) server.getAttribute(Container.ORB_NAME,
467: "ORB");
468: } catch (Throwable t) {
469: log.debug("Unable to retrieve orb" + t.toString());
470: }
471:
472: // Bind the orb
473: if (orb != null) {
474: NonSerializableFactory.rebind(envCtx, "ORB", orb);
475: log.debug("Bound java:comp/ORB");
476: }
477:
478: // Add a link to the global transaction manager
479: envCtx.bind("UserTransaction", new LinkRef(
480: "UserTransaction"));
481: log
482: .debug("Linked java:comp/UserTransaction to JNDI name: UserTransaction");
483: envCtx = envCtx.createSubcontext("env");
484: } finally {
485: currentThread.setContextClassLoader(currentLoader);
486: }
487:
488: Iterator envEntries = metaData.getEnvironmentEntries();
489: log.debug("addEnvEntries");
490: addEnvEntries(envEntries, envCtx);
491: Iterator resourceEnvRefs = metaData.getResourceEnvReferences();
492: log.debug("linkResourceEnvRefs");
493: linkResourceEnvRefs(resourceEnvRefs, envCtx);
494: Iterator resourceRefs = metaData.getResourceReferences();
495: log.debug("linkResourceRefs");
496: linkResourceRefs(resourceRefs, envCtx);
497: log.debug("linkMessageDestinationRefs");
498: linkMessageDestinationRefs(metaData, envCtx, di);
499: Iterator ejbRefs = metaData.getEjbReferences();
500: log.debug("linkEjbRefs");
501: linkEjbRefs(ejbRefs, envCtx, di);
502: Iterator ejbLocalRefs = metaData.getEjbLocalReferences();
503: log.debug("linkEjbLocalRefs");
504: linkEjbLocalRefs(ejbLocalRefs, envCtx, di);
505: log.debug("linkServiceRefs");
506: linkServiceRefs(metaData, envCtx, di);
507: String securityDomain = metaData.getSecurityDomain();
508: log.debug("linkSecurityDomain");
509: linkSecurityDomain(securityDomain, envCtx);
510: log.debug("AbstractWebContainer.parseWebAppDescriptors, End");
511: }
512:
513: private void linkServiceRefs(WebMetaData metaData, Context envCtx,
514: DeploymentInfo di) throws NamingException {
515: UnifiedVirtualFile vfsRoot = new URLLoaderAdapter(di.url);
516: for (ServiceRefMetaData sref : metaData.getServiceReferences()
517: .values()) {
518: String refName = sref.getServiceRefName();
519: new ServiceRefDelegate().bindServiceRef(envCtx, refName,
520: vfsRoot, di.ucl, sref);
521: }
522: }
523:
524: protected void addEnvEntries(Iterator envEntries, Context envCtx)
525: throws ClassNotFoundException, NamingException {
526: while (envEntries.hasNext()) {
527: EnvEntryMetaData entry = (EnvEntryMetaData) envEntries
528: .next();
529: log.debug("Binding env-entry: " + entry.getName()
530: + " of type: " + entry.getType() + " to value:"
531: + entry.getValue());
532: EnvEntryMetaData.bindEnvEntry(envCtx, entry);
533: }
534: }
535:
536: protected void linkResourceEnvRefs(Iterator resourceEnvRefs,
537: Context envCtx) throws NamingException {
538: while (resourceEnvRefs.hasNext()) {
539: ResourceEnvRefMetaData ref = (ResourceEnvRefMetaData) resourceEnvRefs
540: .next();
541: String resourceName = ref.getJndiName();
542: String refName = ref.getRefName();
543: if (ref.getType().equals("java.net.URL")) {
544: try {
545: log.debug("Binding '" + refName + "' to URL: "
546: + resourceName);
547: URL url = new URL(resourceName);
548: Util.bind(envCtx, refName, url);
549: } catch (MalformedURLException e) {
550: throw new NamingException("Malformed URL:"
551: + e.getMessage());
552: }
553: } else if (resourceName != null) {
554: log.debug("Linking '" + refName + "' to JNDI name: "
555: + resourceName);
556: Util.bind(envCtx, refName, new LinkRef(resourceName));
557: } else {
558: throw new NamingException(
559: "resource-env-ref: "
560: + refName
561: + " has no valid JNDI binding. Check the jboss-web/resource-env-ref.");
562: }
563: }
564: }
565:
566: protected void linkResourceRefs(Iterator resourceRefs,
567: Context envCtx) throws NamingException {
568: while (resourceRefs.hasNext()) {
569: ResourceRefMetaData ref = (ResourceRefMetaData) resourceRefs
570: .next();
571: String jndiName = ref.getJndiName();
572: String refName = ref.getRefName();
573: if (ref.getType().equals("java.net.URL")) {
574: try {
575: String resURL = ref.getResURL();
576: if (ref.getResURL() != null) {
577: log.debug("Binding '" + refName + "' to URL: "
578: + resURL);
579: URL url = new URL(resURL);
580: Util.bind(envCtx, refName, url);
581: } else {
582: log.debug("Linking '" + refName + "' to URL: "
583: + resURL);
584: LinkRef urlLink = new LinkRef(jndiName);
585: Util.bind(envCtx, refName, urlLink);
586: }
587: } catch (MalformedURLException e) {
588: throw new NamingException("Malformed URL:"
589: + e.getMessage());
590: }
591: } else if (jndiName != null) {
592: log.debug("Linking '" + refName + "' to JNDI name: "
593: + jndiName);
594: Util.bind(envCtx, refName, new LinkRef(jndiName));
595: } else {
596: throw new NamingException(
597: "resource-ref: "
598: + refName
599: + " has no valid JNDI binding. Check the jboss-web/resource-ref.");
600: }
601: }
602: }
603:
604: protected void linkMessageDestinationRefs(WebMetaData metaData,
605: Context envCtx, DeploymentInfo di) throws NamingException,
606: DeploymentException {
607: Iterator i = metaData.getMessageDestinationReferences();
608:
609: while (i.hasNext()) {
610: MessageDestinationRefMetaData ref = (MessageDestinationRefMetaData) i
611: .next();
612:
613: String refName = ref.getRefName();
614: String jndiName = ref.getJNDIName();
615: String link = ref.getLink();
616: if (link != null) {
617: if (jndiName == null) {
618: MessageDestinationMetaData messageDestination = EjbUtil
619: .findMessageDestination(server, di, link);
620: if (messageDestination == null)
621: throw new DeploymentException(
622: "message-destination-ref '"
623: + refName
624: + "' message-destination-link '"
625: + link
626: + "' not found and no jndi-name in jboss-web.xml");
627: else {
628: String linkJNDIName = messageDestination
629: .getJNDIName();
630: if (linkJNDIName == null)
631: log
632: .warn("message-destination '"
633: + link
634: + "' has no jndi-name in jboss-web.xml");
635: else
636: jndiName = linkJNDIName;
637: }
638: } else
639: log
640: .warn("message-destination-ref '"
641: + refName
642: + "' ignoring message-destination-link '"
643: + link
644: + "' because it has a jndi-name in jboss-web.xml");
645: } else if (jndiName == null)
646: throw new DeploymentException(
647: "message-destination-ref '"
648: + refName
649: + "' has no message-destination-link in web.xml and no jndi-name in jboss-web.xml");
650: Util.bind(envCtx, refName, new LinkRef(jndiName));
651: }
652: }
653:
654: protected void linkEjbRefs(Iterator ejbRefs, Context envCtx,
655: DeploymentInfo di) throws NamingException {
656: while (ejbRefs.hasNext()) {
657: EjbRefMetaData ejb = (EjbRefMetaData) ejbRefs.next();
658: String name = ejb.getName();
659: String linkName = ejb.getLink();
660: String jndiName = null;
661:
662: //use ejb-link if it is specified
663: if (linkName != null) {
664: jndiName = EjbUtil.findEjbLink(server, di, linkName);
665:
666: //if flag does not allow misconfigured ejb-links, it is an error
667: if ((jndiName == null) && !(getLenientEjbLink()))
668: throw new NamingException("ejb-ref: " + name
669: + ", no ejb-link match");
670: }
671:
672: //fall through to the jndiName
673: if (jndiName == null) {
674: jndiName = ejb.getJndiName();
675: if (jndiName == null)
676: throw new NamingException(
677: "ejb-ref: "
678: + name
679: + ", no ejb-link in web.xml and no jndi-name in jboss-web.xml");
680: }
681:
682: log.debug("Linking ejb-ref: " + name + " to JNDI name: "
683: + jndiName);
684: Util.bind(envCtx, name, new LinkRef(jndiName));
685: }
686: }
687:
688: protected void linkEjbLocalRefs(Iterator ejbRefs, Context envCtx,
689: DeploymentInfo di) throws NamingException {
690: while (ejbRefs.hasNext()) {
691: EjbLocalRefMetaData ejb = (EjbLocalRefMetaData) ejbRefs
692: .next();
693: String name = ejb.getName();
694: String linkName = ejb.getLink();
695: String jndiName = null;
696:
697: //use the ejb-link field if it is specified
698: if (linkName != null) {
699: jndiName = EjbUtil.findLocalEjbLink(server, di,
700: linkName);
701:
702: //if flag does not allow misconfigured ejb-links, it is an error
703: if ((jndiName == null) && !(getLenientEjbLink()))
704: throw new NamingException("ejb-ref: " + name
705: + ", no ejb-link match");
706: }
707:
708: if (jndiName == null) {
709: jndiName = ejb.getJndiName();
710: if (jndiName == null) {
711: String msg = null;
712: if (linkName == null) {
713: msg = "ejb-local-ref: '" + name
714: + "', no ejb-link in web.xml and "
715: + "no local-jndi-name in jboss-web.xml";
716: } else {
717: msg = "ejb-local-ref: '"
718: + name
719: + "', with web.xml ejb-link: '"
720: + linkName
721: + "' failed to resolve to an ejb with a LocalHome";
722: }
723: throw new NamingException(msg);
724: }
725: }
726:
727: log.debug("Linking ejb-local-ref: " + name
728: + " to JNDI name: " + jndiName);
729: Util.bind(envCtx, name, new LinkRef(jndiName));
730: }
731: }
732:
733: /** This creates a java:comp/env/security context that contains a
734: securityMgr binding pointing to an AuthenticationManager implementation
735: and a realmMapping binding pointing to a RealmMapping implementation.
736: If the jboss-web.xml descriptor contained a security-domain element
737: then the bindings are LinkRefs to the jndi name specified by the
738: security-domain element. If there was no security-domain element then
739: the bindings are to NullSecurityManager instance which simply allows
740: all access.
741: */
742: protected void linkSecurityDomain(String securityDomain,
743: Context envCtx) throws NamingException {
744: if (securityDomain == null) {
745: securityDomain = getDefaultSecurityDomain();
746: log.debug("No security-domain given, using default: "
747: + securityDomain);
748: }
749: log.debug("Linking security/securityMgr to JNDI name: "
750: + securityDomain);
751: Util.bind(envCtx, "security/securityMgr", new LinkRef(
752: securityDomain));
753: Util.bind(envCtx, "security/realmMapping", new LinkRef(
754: securityDomain));
755: Util.bind(envCtx, "security/security-domain", new LinkRef(
756: securityDomain));
757: Util.bind(envCtx, "security/subject", new LinkRef(
758: securityDomain + "/subject"));
759: }
760:
761: /** A utility method that searches the given loader for the
762: resources: "javax/servlet/resources/web-app_2_3.dtd",
763: "org/apache/jasper/resources/jsp12.dtd", and "javax/ejb/EJBHome.class"
764: and returns an array of URL strings. Any jar: urls are reduced to the
765: underlying <url> portion of the 'jar:<url>!/{entry}' construct.
766: */
767: public String[] getStandardCompileClasspath(ClassLoader loader) {
768: String[] jspResources = {
769: "javax/servlet/resources/web-app_2_3.dtd",
770: "org/apache/jasper/resources/jsp12.dtd",
771: "javax/ejb/EJBHome.class" };
772: ArrayList tmp = new ArrayList();
773: for (int j = 0; j < jspResources.length; j++) {
774: URL rsrcURL = loader.getResource(jspResources[j]);
775: if (rsrcURL != null) {
776: String url = rsrcURL.toExternalForm();
777: if (rsrcURL.getProtocol().equals("jar")) {
778: // Parse the jar:<url>!/{entry} URL
779: url = url.substring(4);
780: int seperator = url.indexOf('!');
781: url = url.substring(0, seperator);
782: }
783: tmp.add(url);
784: } else {
785: log.warn("Failed to fin jsp rsrc: " + jspResources[j]);
786: }
787: }
788: log.trace("JSP StandardCompileClasspath: " + tmp);
789: String[] cp = new String[tmp.size()];
790: tmp.toArray(cp);
791: return cp;
792: }
793:
794: /** A utility method that walks up the ClassLoader chain starting at
795: the given loader and queries each ClassLoader for a 'URL[] getURLs()'
796: method from which a complete classpath of URL strings is built.
797: */
798: public String[] getCompileClasspath(ClassLoader loader) {
799: HashSet tmp = new HashSet();
800: ClassLoader cl = loader;
801: while (cl != null) {
802: URL[] urls = AbstractWebContainer.getClassLoaderURLs(cl);
803: addURLs(tmp, urls);
804: cl = cl.getParent();
805: }
806: try {
807: URL[] globalUrls = (URL[]) server.getAttribute(
808: LoaderRepositoryFactory.DEFAULT_LOADER_REPOSITORY,
809: "URLs");
810: addURLs(tmp, globalUrls);
811: } catch (Exception e) {
812: log
813: .warn(
814: "Could not get global URL[] from default loader repository!",
815: e);
816: } // end of try-catch
817: log.trace("JSP CompileClasspath: " + tmp);
818: String[] cp = new String[tmp.size()];
819: tmp.toArray(cp);
820: return cp;
821: }
822:
823: private void addURLs(Set urlSet, URL[] urls) {
824: for (int u = 0; u < urls.length; u++) {
825: URL url = urls[u];
826: urlSet.add(url.toExternalForm());
827: }
828: }
829:
830: /** Create the JACC permission based on the security constraints obtained
831: * from the web.xml metadata.
832: *
833: * @param metaData
834: * @param pc
835: * @throws PolicyContextException
836: */
837: protected void createPermissions(WebMetaData metaData,
838: PolicyConfiguration pc) throws PolicyContextException {
839: WebPermissionMapping.createPermissions(metaData, pc);
840: }
841:
842: /** An inner class that maps the WebDescriptorParser.parseWebAppDescriptors()
843: onto the protected parseWebAppDescriptors() AbstractWebContainer method.
844: */
845: private class DescriptorParser implements WebDescriptorParser {
846: DeploymentInfo di;
847:
848: DescriptorParser(DeploymentInfo di) {
849: this .di = di;
850: }
851:
852: public void parseWebAppDescriptors(ClassLoader loader,
853: WebMetaData metaData) throws Exception {
854: AbstractWebDeployer.this .parseWebAppDescriptors(di, loader,
855: metaData);
856: }
857:
858: public DeploymentInfo getDeploymentInfo() {
859: return di;
860: }
861: }
862: }
|