View Javadoc

1   // ========================================================================
2   // Copyright (c) 2006-2010 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.plus.webapp;
15  
16  import java.util.Iterator;
17  
18  import javax.naming.Context;
19  import javax.naming.InitialContext;
20  import javax.naming.NameNotFoundException;
21  
22  import org.eclipse.jetty.jndi.NamingUtil;
23  import org.eclipse.jetty.plus.annotation.Injection;
24  import org.eclipse.jetty.plus.annotation.InjectionCollection;
25  import org.eclipse.jetty.plus.annotation.LifeCycleCallback;
26  import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection;
27  import org.eclipse.jetty.plus.annotation.PostConstructCallback;
28  import org.eclipse.jetty.plus.annotation.PreDestroyCallback;
29  import org.eclipse.jetty.plus.annotation.RunAsCollection;
30  import org.eclipse.jetty.plus.jndi.EnvEntry;
31  import org.eclipse.jetty.plus.jndi.Link;
32  import org.eclipse.jetty.plus.jndi.NamingEntry;
33  import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
34  import org.eclipse.jetty.util.TypeUtil;
35  import org.eclipse.jetty.util.log.Log;
36  import org.eclipse.jetty.webapp.Descriptor;
37  import org.eclipse.jetty.webapp.FragmentDescriptor;
38  import org.eclipse.jetty.webapp.IterativeDescriptorProcessor;
39  import org.eclipse.jetty.webapp.WebAppContext;
40  import org.eclipse.jetty.webapp.MetaData;
41  import org.eclipse.jetty.webapp.MetaData.Origin;
42  import org.eclipse.jetty.xml.XmlParser;
43  
44  /**
45   * PlusDescriptorProcessor
46   *
47   *
48   */
49  
50  public class PlusDescriptorProcessor extends IterativeDescriptorProcessor
51  {
52      public PlusDescriptorProcessor ()
53      {
54          try
55          {
56              registerVisitor("env-entry", getClass().getDeclaredMethod("visitEnvEntry", __signature));
57              registerVisitor("resource-ref", getClass().getDeclaredMethod("visitResourceRef", __signature));
58              registerVisitor("resource-env-ref", getClass().getDeclaredMethod("visitResourceEnvRef", __signature));
59              registerVisitor("message-destination-ref", getClass().getDeclaredMethod("visitMessageDestinationRef", __signature));
60              registerVisitor("post-construct", getClass().getDeclaredMethod("visitPostConstruct", __signature));
61              registerVisitor("pre-destroy", getClass().getDeclaredMethod("visitPreDestroy", __signature));
62          }
63          catch (Exception e)
64          {
65              throw new IllegalStateException(e);
66          }
67      }
68  
69      /** 
70       * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#start(WebAppContext, org.eclipse.jetty.webapp.Descriptor)
71       */
72      public void start(WebAppContext context, Descriptor descriptor)
73      { 
74  
75          InjectionCollection injections = (InjectionCollection)context.getAttribute(InjectionCollection.INJECTION_COLLECTION);
76          if (injections == null)
77          {
78              injections = new InjectionCollection();
79              context.setAttribute(InjectionCollection.INJECTION_COLLECTION, injections);
80          }
81  
82          LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION);
83          if (callbacks == null)
84          {
85              callbacks = new LifeCycleCallbackCollection();
86              context.setAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION, callbacks);
87          }
88  
89          RunAsCollection runAsCollection = (RunAsCollection)context.getAttribute(RunAsCollection.RUNAS_COLLECTION);
90          if (runAsCollection == null)
91          {
92              runAsCollection = new RunAsCollection();
93              context.setAttribute(RunAsCollection.RUNAS_COLLECTION, runAsCollection);  
94          }
95      }
96  
97      
98      /** 
99       * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#end(org.eclipse.jetty.webapp.Descriptor, WebAppContext)
100      */
101     public void end(WebAppContext context,Descriptor descriptor)
102     {
103     }
104 
105     
106    
107     
108     /**
109      * JavaEE 5.4.1.3 
110      * 
111      * @param node
112      * @throws Exception
113      */
114     public void visitEnvEntry (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
115     throws Exception
116     {
117         String name=node.getString("env-entry-name",false,true);
118         String type = node.getString("env-entry-type",false,true);
119         String valueStr = node.getString("env-entry-value",false,true);
120         
121         //if there's no value there's no point in making a jndi entry
122         //nor processing injection entries
123         if (valueStr==null || valueStr.equals(""))
124         {
125             Log.warn("No value for env-entry-name "+name);
126             return;
127         }
128         
129         Origin o = context.getMetaData().getOrigin("env-entry."+name);
130         switch (o)
131         {
132             case NotSet:
133             {
134                 //no descriptor has configured an env-entry of this name previously
135                 context.getMetaData().setOrigin("env-entry."+name, descriptor);
136                 //the javaee_5.xsd says that the env-entry-type is optional
137                 //if there is an <injection> element, because you can get
138                 //type from the element, but what to do if there is more
139                 //than one <injection> element, do you just pick the type
140                 //of the first one?
141                 addInjections (context, descriptor, node, name, TypeUtil.fromName(type));
142                 Object value = TypeUtil.valueOf(type,valueStr);
143                 bindEnvEntry(name, value);   
144                 break;
145             }
146             case WebXml:
147             case WebDefaults:
148             case WebOverride:
149             {
150                 //ServletSpec 3.0 p75. web.xml (or web-override/web-defaults) declared
151                 //the env-entry. A fragment is not allowed to change that, except unless
152                 //the web.xml did not declare any injections.
153                 if (!(descriptor instanceof FragmentDescriptor))
154                 {
155                     //We're processing web-defaults, web.xml or web-override. Any of them can
156                     //set or change the env-entry.
157                     context.getMetaData().setOrigin("env-entry."+name, descriptor);
158                     addInjections (context, descriptor, node, name, TypeUtil.fromName(type));
159                     Object value = TypeUtil.valueOf(type,valueStr);
160                     bindEnvEntry(name, value);   
161                 }
162                 else
163                 {
164                     //A web.xml declared the env-entry. Check to see if any injections have been
165                     //declared for it. If it was declared in web.xml then don't merge any injections.
166                     //If it was declared in a web-fragment, then we can keep merging fragments.
167                     Descriptor d = context.getMetaData().getOriginDescriptor("env-entry."+name+".injection");
168                     if (d==null || d instanceof FragmentDescriptor)
169                         addInjections(context, descriptor, node, name, TypeUtil.fromName(type));
170                 }
171                 break;
172             }
173             case WebFragment:
174             {
175                 //ServletSpec p.75. No declaration in web.xml, but in multiple web-fragments. Error.
176                 throw new IllegalStateException("Conflicting env-entry "+name+" in "+descriptor.getResource());
177             }
178         }
179     }
180     
181     
182     /**
183      * Common Annotations Spec section 2.3:
184      *  resource-ref is for:
185      *    - javax.sql.DataSource
186      *    - javax.jms.ConnectionFactory
187      *    - javax.jms.QueueConnectionFactory
188      *    - javax.jms.TopicConnectionFactory
189      *    - javax.mail.Session
190      *    - java.net.URL
191      *    - javax.resource.cci.ConnectionFactory
192      *    - org.omg.CORBA_2_3.ORB
193      *    - any other connection factory defined by a resource adapter
194      *    
195      * TODO
196      * If web.xml contains a resource-ref with injection targets, all resource-ref entries
197      * of the same name are ignored in web fragments. If web.xml does not contain any
198      * injection-targets, then they are merged from all the fragments. 
199      * If web.xml does not contain a resource-ref element of same name, but 2 fragments
200      * declare the same name it is an error.
201      * resource-ref entries are ONLY for connection factories
202      * the resource-ref says how the app will reference the jndi lookup relative
203      * to java:comp/env, but it is up to the deployer to map this reference to
204      * a real resource in the environment. At the moment, we insist that the
205      * jetty.xml file name of the resource has to be exactly the same as the
206      * name in web.xml deployment descriptor, but it shouldn't have to be
207      * 
208      * @param node
209      * @throws Exception
210      */
211     public void visitResourceRef (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
212     throws Exception
213     {
214         String jndiName = node.getString("res-ref-name",false,true);
215         String type = node.getString("res-type", false, true);
216         String auth = node.getString("res-auth", false, true);
217         String shared = node.getString("res-sharing-scope", false, true);
218         
219         Origin o = context.getMetaData().getOrigin("resource-ref."+jndiName);
220         switch (o)
221         {
222             case NotSet:
223             {
224                 //No descriptor or annotation previously declared a resource-ref of this name.
225                 context.getMetaData().setOrigin("resource-ref."+jndiName, descriptor);
226                 
227                 //check for <injection> elements
228                 Class<?> typeClass = TypeUtil.fromName(type);
229                 if (typeClass==null)
230                     typeClass = context.loadClass(type);
231                 addInjections(context, descriptor, node, jndiName, typeClass);                  
232                 bindResourceRef(context,jndiName, typeClass);
233                 break;
234             }
235             case WebXml:
236             case WebDefaults:
237             case WebOverride:   
238             {
239                 //A web xml previously declared the resource-ref.    
240                 if (!(descriptor instanceof FragmentDescriptor))
241                 {
242                     //We're processing web-defaults, web.xml or web-override. Any of them can
243                     //set or change the resource-ref.
244                     context.getMetaData().setOrigin("resource-ref."+jndiName, descriptor);
245      
246                     //check for <injection> elements
247                     Class<?> typeClass = TypeUtil.fromName(type);
248                     if (typeClass==null)
249                         typeClass = context.loadClass(type);
250                     
251                     addInjections(context, descriptor, node, jndiName, typeClass);
252                    
253                     //bind the entry into jndi
254                     bindResourceRef(context,jndiName, typeClass);
255                 }
256                 else
257                 {
258                     //A web xml declared the resource-ref and we're processing a 
259                     //web-fragment. Check to see if any injections were declared for it by web.xml. 
260                     //If any injection was declared in web.xml then don't merge any injections.
261                     //If it was declared in a web-fragment, then we can keep merging fragments.
262                     Descriptor d = context.getMetaData().getOriginDescriptor("resource-ref."+jndiName+".injection");
263                     if (d==null || d instanceof FragmentDescriptor)
264                     { 
265                         Class<?> typeClass = TypeUtil.fromName(type);
266                         if (typeClass==null)
267                             typeClass = context.loadClass(type);
268                         addInjections(context, descriptor, node, jndiName, TypeUtil.fromName(type));
269                     }
270                 }
271                 break;
272             }
273             case WebFragment:
274             { 
275                 //ServletSpec p.75. No declaration of resource-ref in web xml, but in multiple web-fragments. Error.
276                 throw new IllegalStateException("Conflicting resource-ref "+jndiName+" in "+descriptor.getResource());
277             }
278         }
279       
280     }
281     
282     
283     /**
284      * Common Annotations Spec section 2.3:
285      *   resource-env-ref is for:
286      *     - javax.transaction.UserTransaction
287      *     - javax.resource.cci.InteractionSpec
288      *     - anything else that is not a connection factory
289      *     
290      * @param node
291      * @throws Exception
292      */
293     public void visitResourceEnvRef (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
294     throws Exception
295     {
296         String jndiName = node.getString("resource-env-ref-name",false,true);
297         String type = node.getString("resource-env-ref-type", false, true);
298         
299         Origin o = context.getMetaData().getOrigin("resource-env-ref."+jndiName);
300         switch (o)
301         {
302             case NotSet:
303             {
304                 //First declaration of resource-env-ref with this jndiName
305                 //JavaEE Spec sec 5.7.1.3 says the resource-env-ref-type
306                 //is mandatory, but the schema says it is optional!
307                 Class<?> typeClass = TypeUtil.fromName(type);
308                 if (typeClass==null)
309                     typeClass = context.loadClass(type);
310                 addInjections (context, descriptor, node, jndiName, typeClass);
311                 bindResourceEnvRef(context,jndiName, typeClass);
312              break;
313             }
314             case WebXml:
315             case WebDefaults:
316             case WebOverride:   
317             {
318                 //A resource-env-ref of this name has been declared first in a web xml.
319                 //Only allow other web-default, web.xml, web-override to change it.
320                 if (!(descriptor instanceof FragmentDescriptor))
321                 {
322                     //We're processing web-defaults, web.xml or web-override. Any of them can
323                     //set or change the resource-env-ref.
324                     context.getMetaData().setOrigin("resource-env-ref."+jndiName, descriptor);
325                     Class<?> typeClass = TypeUtil.fromName(type);
326                     if (typeClass==null)
327                         typeClass = context.loadClass(type);
328                     addInjections (context, descriptor, node, jndiName, typeClass);
329                     bindResourceEnvRef(context,jndiName, typeClass); 
330                 }
331                 else
332                 {
333                     //We're processing a web-fragment. It can only contribute injections if the
334                     //there haven't been any injections declared yet, or they weren't declared in a WebXml file.
335                     Descriptor d = context.getMetaData().getOriginDescriptor("resource-env-ref."+jndiName+".injection");
336                     if (d == null || d instanceof FragmentDescriptor)
337                     {
338                         Class<?> typeClass = TypeUtil.fromName(type);
339                         if (typeClass==null)
340                             typeClass = context.loadClass(type);
341                         addInjections (context, descriptor, node, jndiName, typeClass);
342                     }
343                 }
344                 break;
345             }
346             case WebFragment:
347             {
348                 //ServletSpec p.75. No declaration of resource-env-ref in web xml, but in multiple web-fragments. Error.
349                 throw new IllegalStateException("Conflicting resource-env-ref "+jndiName+" in "+descriptor.getResource()); 
350             }
351         }
352     }
353     
354     
355     /**
356      * Common Annotations Spec section 2.3:
357      *   message-destination-ref is for:
358      *     - javax.jms.Queue
359      *     - javax.jms.Topic
360      * @param node
361      * @throws Exception
362      */
363     public void visitMessageDestinationRef (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
364     throws Exception
365     {
366         String jndiName = node.getString("message-destination-ref-name",false,true);
367         String type = node.getString("message-destination-type",false,true);
368         String usage = node.getString("message-destination-usage",false,true);
369         
370         Origin o = context.getMetaData().getOrigin("message-destination-ref."+jndiName);
371         switch (o)
372         {
373             case NotSet:
374             {       
375                 //A message-destination-ref of this name has not been previously declared
376                 Class<?> typeClass = TypeUtil.fromName(type);
377                 if (typeClass==null)
378                     typeClass = context.loadClass(type);
379                 addInjections(context, descriptor, node, jndiName, typeClass);   
380                 bindMessageDestinationRef(context,jndiName, typeClass);
381                 context.getMetaData().setOrigin("message-destination-ref."+jndiName, descriptor);
382                 break;
383             }
384             case WebXml:
385             case WebDefaults:
386             case WebOverride:   
387             {               
388                 //A message-destination-ref of this name has been declared first in a web xml.
389                 //Only allow other web-default, web.xml, web-override to change it.
390                 if (!(descriptor instanceof FragmentDescriptor))
391                 {
392                     Class<?> typeClass = TypeUtil.fromName(type);
393                     if (typeClass==null)
394                         typeClass = context.loadClass(type);
395                     addInjections(context, descriptor, node, jndiName, typeClass);   
396                     bindMessageDestinationRef(context,jndiName, typeClass);
397                     context.getMetaData().setOrigin("message-destination-ref."+jndiName, descriptor);
398                 }
399                 else
400                 {
401                     //A web-fragment has declared a message-destination-ref with the same name as a web xml.
402                     //It can only contribute injections, and only if the web xml didn't declare any.
403                     Descriptor d = context.getMetaData().getOriginDescriptor("message-destination-ref."+jndiName+".injection");
404                     if (d == null || d instanceof FragmentDescriptor)
405                     { 
406                         Class<?> typeClass = TypeUtil.fromName(type);
407                         if (typeClass==null)
408                             typeClass = context.loadClass(type);
409                         addInjections(context, descriptor, node, jndiName, typeClass);   
410                     }
411                 }
412                 break;
413             }
414             case WebFragment:
415             {
416               //ServletSpec p.75. No declaration of message-destination-ref in web xml, but in multiple web-fragments. Error.
417                 throw new IllegalStateException("Conflicting message-destination-ref "+jndiName+" in "+descriptor.getResource());  
418             }
419         }
420 
421     }
422     
423     
424 
425     /**
426      * 
427      * TODO
428      * If web.xml has at least 1 post-construct, then all post-constructs in fragments
429      * are ignored. Otherwise, post-constructs from fragments are merged.
430      * post-construct is the name of a class and method to call after all
431      * resources have been setup but before the class is put into use
432      * @param node
433      */
434     public void visitPostConstruct(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
435     {
436         String className = node.getString("lifecycle-callback-class", false, true);
437         String methodName = node.getString("lifecycle-callback-method", false, true);
438         
439         if (className==null || className.equals(""))
440         {
441             Log.warn("No lifecycle-callback-class specified");
442             return;
443         }
444         if (methodName==null || methodName.equals(""))
445         {
446             Log.warn("No lifecycle-callback-method specified for class "+className);
447             return;
448         }
449        
450         //ServletSpec 3.0 p80 If web.xml declares a post-construct then all post-constructs
451         //in fragments must be ignored. Otherwise, they are additive.
452         Origin o = context.getMetaData().getOrigin("post-construct");
453         switch (o)
454         {
455             case NotSet:
456             {
457                 //No post-constructs have been declared previously.
458                 context.getMetaData().setOrigin("post-construct", descriptor);
459                 
460                 try
461                 {
462                     Class<?> clazz = context.loadClass(className);
463                     LifeCycleCallback callback = new PostConstructCallback();
464                     callback.setTarget(clazz, methodName);
465                     ((LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)).add(callback);
466                 }
467                 catch (ClassNotFoundException e)
468                 {
469                     Log.warn("Couldn't load post-construct target class "+className);
470                 }
471                 break;
472             }
473             case WebXml:
474             case WebDefaults:
475             case WebOverride:   
476             {
477                 //A web xml first declared a post-construct. Only allow other web xml files (web-defaults, web-overrides etc)
478                 //to add to it
479                 if (!(descriptor instanceof FragmentDescriptor))
480                 {
481                     try
482                     {
483                         Class<?> clazz = context.loadClass(className);
484                         LifeCycleCallback callback = new PostConstructCallback();
485                         callback.setTarget(clazz, methodName);
486                         ((LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)).add(callback);
487                     }
488                     catch (ClassNotFoundException e)
489                     {
490                         Log.warn("Couldn't load post-construct target class "+className);
491                     }
492                 }
493                 break;
494             }
495             case WebFragment:
496             {
497                 //A web-fragment first declared a post-construct. Allow all other web-fragments to merge in their post-constructs
498                 try
499                 {
500                     Class<?> clazz = context.loadClass(className);
501                     LifeCycleCallback callback = new PostConstructCallback();
502                     callback.setTarget(clazz, methodName);
503                     ((LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)).add(callback);
504                 }
505                 catch (ClassNotFoundException e)
506                 {
507                     Log.warn("Couldn't load post-construct target class "+className);
508                 }
509                 break;
510             }
511         }
512       
513     }
514     
515 
516     /**
517      * 
518      * pre-destroy is the name of a class and method to call just as
519      * the instance is being destroyed
520      * @param node
521      */
522     public void visitPreDestroy(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
523     {
524         String className = node.getString("lifecycle-callback-class", false, true);
525         String methodName = node.getString("lifecycle-callback-method", false, true);
526         if (className==null || className.equals(""))
527         {
528             Log.warn("No lifecycle-callback-class specified for pre-destroy");
529             return;
530         }
531         if (methodName==null || methodName.equals(""))
532         {
533             Log.warn("No lifecycle-callback-method specified for pre-destroy class "+className);
534             return;
535         } 
536       
537         Origin o = context.getMetaData().getOrigin("pre-destroy");
538         switch(o)
539         {
540             case NotSet:
541             {
542                 //No pre-destroys have been declared previously. Record this descriptor
543                 //as the first declarer.
544                 context.getMetaData().setOrigin("pre-destroy", descriptor);
545                 try
546                 {
547                     Class<?> clazz = context.loadClass(className);
548                     LifeCycleCallback callback = new PreDestroyCallback();
549                     callback.setTarget(clazz, methodName);
550                     ((LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)).add(callback);
551                 }
552                 catch (ClassNotFoundException e)
553                 {
554                     Log.warn("Couldn't load pre-destory target class "+className);
555                 }
556                 break;
557             }
558             case WebXml:
559             case WebDefaults:
560             case WebOverride:   
561             {
562                 //A web xml file previously declared a pre-destroy. Only allow other web xml files
563                 //(not web-fragments) to add to them.
564                 if (!(descriptor instanceof FragmentDescriptor))
565                 {
566                     try
567                     {
568                         Class<?> clazz = context.loadClass(className);
569                         LifeCycleCallback callback = new PreDestroyCallback();
570                         callback.setTarget(clazz, methodName);
571                         ((LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)).add(callback);
572                     }
573                     catch (ClassNotFoundException e)
574                     {
575                         Log.warn("Couldn't load pre-destory target class "+className);
576                     } 
577                 }
578                 break;
579             }
580             case WebFragment:
581             {
582                 //No pre-destroys in web xml, so allow all fragments to merge their pre-destroys.
583                 try
584                 {
585                     Class<?> clazz = context.loadClass(className);
586                     LifeCycleCallback callback = new PreDestroyCallback();
587                     callback.setTarget(clazz, methodName);
588                     ((LifeCycleCallbackCollection)context.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)).add(callback);
589                 }
590                 catch (ClassNotFoundException e)
591                 {
592                     Log.warn("Couldn't load pre-destory target class "+className);
593                 } 
594                 break;
595             }
596         }  
597     }
598     
599     
600     /**
601      * Iterate over the &lt;injection-target&gt; entries for a node
602      * 
603      * @param descriptor
604      * @param node
605      * @param jndiName
606      * @param valueClass
607      * @return 
608      */
609     public void addInjections (WebAppContext context, Descriptor descriptor, XmlParser.Node node, String jndiName, Class<?> valueClass)
610     {
611         Iterator  itor = node.iterator("injection-target");
612         
613         while(itor.hasNext())
614         {
615             XmlParser.Node injectionNode = (XmlParser.Node)itor.next(); 
616             String targetClassName = injectionNode.getString("injection-target-class", false, true);
617             String targetName = injectionNode.getString("injection-target-name", false, true);
618             if ((targetClassName==null) || targetClassName.equals(""))
619             {
620                 Log.warn("No classname found in injection-target");
621                 continue;
622             }
623             if ((targetName==null) || targetName.equals(""))
624             {
625                 Log.warn("No field or method name in injection-target");
626                 continue;
627             }
628 
629             InjectionCollection injections = (InjectionCollection)context.getAttribute(InjectionCollection.INJECTION_COLLECTION);
630             if (injections == null)
631             {
632                 injections = new InjectionCollection();
633                 context.setAttribute(InjectionCollection.INJECTION_COLLECTION, injections);
634             }
635             // comments in the javaee_5.xsd file specify that the targetName is looked
636             // for first as a java bean property, then if that fails, as a field
637             try
638             {
639                 Class<?> clazz = context.loadClass(targetClassName);
640                 Injection injection = new Injection();
641                 injection.setJndiName(jndiName);
642                 injection.setTarget(clazz, targetName, valueClass);
643                 injections.add(injection);
644                 
645                 //Record which was the first descriptor to declare an injection for this name
646                 if (context.getMetaData().getOriginDescriptor(node.getTag()+"."+jndiName+".injection") == null)
647                     context.getMetaData().setOrigin(node.getTag()+"."+jndiName+".injection", descriptor);
648             }
649             catch (ClassNotFoundException e)
650             {
651                 Log.warn("Couldn't load injection target class "+targetClassName);
652             }
653         }
654     }
655     
656   
657 
658     
659     /** 
660      * @see org.eclipse.jetty.plus.webapp.AbstractConfiguration#bindEnvEntry(java.lang.String, java.lang.String)
661      * @param name
662      * @param value
663      * @throws Exception
664      */
665     public void bindEnvEntry(String name, Object value) throws Exception
666     {    
667         InitialContext ic = null;
668         boolean bound = false;
669         //check to see if we bound a value and an EnvEntry with this name already
670         //when we processed the server and the webapp's naming environment
671         //@see EnvConfiguration.bindEnvEntries()
672         ic = new InitialContext();
673         try
674         {
675             NamingEntry ne = (NamingEntry)ic.lookup("java:comp/env/"+NamingEntryUtil.makeNamingEntryName(ic.getNameParser(""), name));
676             if (ne!=null && ne instanceof EnvEntry)
677             {
678                 EnvEntry ee = (EnvEntry)ne;
679                 bound = ee.isOverrideWebXml();
680             }
681         }
682         catch (NameNotFoundException e)
683         {
684             bound = false;
685         }
686 
687         if (!bound)
688         {
689             //either nothing was bound or the value from web.xml should override
690             Context envCtx = (Context)ic.lookup("java:comp/env");
691             NamingUtil.bind(envCtx, name, value);
692         }
693     }
694 
695     /** 
696      * Bind a resource reference.
697      * 
698      * If a resource reference with the same name is in a jetty-env.xml
699      * file, it will already have been bound.
700      * 
701      * @see org.eclipse.jetty.plus.webapp.AbstractConfiguration#bindResourceRef(java.lang.String)
702      * @param name
703      * @throws Exception
704      */
705     public void bindResourceRef(WebAppContext context, String name, Class<?> typeClass)
706     throws Exception
707     {
708         bindEntry(context, name, typeClass);
709     }
710 
711     /** 
712      * @see org.eclipse.jetty.plus.webapp.AbstractConfiguration#bindResourceEnvRef(java.lang.String)
713      * @param name
714      * @throws Exception
715      */
716     public void bindResourceEnvRef(WebAppContext context, String name, Class<?> typeClass)
717     throws Exception
718     {
719         bindEntry(context, name, typeClass);
720     }
721     
722     
723     public void bindMessageDestinationRef(WebAppContext context, String name, Class<?> typeClass)
724     throws Exception
725     {
726         bindEntry(context, name, typeClass);
727     }
728    
729     
730     /**
731      * Bind a resource with the given name from web.xml of the given type
732      * with a jndi resource from either the server or the webapp's naming 
733      * environment.
734      * 
735      * As the servlet spec does not cover the mapping of names in web.xml with
736      * names from the execution environment, jetty uses the concept of a Link, which is
737      * a subclass of the NamingEntry class. A Link defines a mapping of a name
738      * from web.xml with a name from the execution environment (ie either the server or the
739      * webapp's naming environment).
740      * 
741      * @param name name of the resource from web.xml
742      * @param typeClass 
743      * @throws Exception
744      */
745     protected void bindEntry (WebAppContext context, String name, Class<?> typeClass)
746     throws Exception
747     {
748         String nameInEnvironment = name;
749         boolean bound = false;
750         
751         //check if the name in web.xml has been mapped to something else
752         //check a context-specific naming environment first
753         Object scope = context;
754         NamingEntry ne = NamingEntryUtil.lookupNamingEntry(scope, name);
755     
756         if (ne!=null && (ne instanceof Link))
757         {
758             //if we found a mapping, get out name it is mapped to in the environment
759             nameInEnvironment = (String)((Link)ne).getObjectToBind();
760             Link l = (Link)ne;
761         }
762 
763         //try finding that mapped name in the webapp's environment first
764         scope = context;
765         bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment);
766         
767         if (bound)
768             return;
769         
770         //try the server's environment
771         scope = context.getServer();
772         bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment);
773         if (bound)
774             return;
775 
776         //try the jvm environment
777         bound = NamingEntryUtil.bindToENC(null, name, nameInEnvironment);
778         if (bound)
779             return;
780 
781         //There is no matching resource so try a default name.
782         //The default name syntax is: the [res-type]/default
783         //eg       javax.sql.DataSource/default
784         nameInEnvironment = typeClass.getName()+"/default";
785         //First try the server scope
786         NamingEntry defaultNE = NamingEntryUtil.lookupNamingEntry(context.getServer(), nameInEnvironment);
787         if (defaultNE==null)
788             defaultNE = NamingEntryUtil.lookupNamingEntry(null, nameInEnvironment);
789         
790         if (defaultNE!=null)
791             defaultNE.bindToENC(name);
792         else
793             throw new IllegalStateException("Nothing to bind for name "+nameInEnvironment);
794     }
795 
796  
797 }