View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.osgi.annotations;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  import org.eclipse.jetty.annotations.AbstractDiscoverableAnnotationHandler;
25  import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
26  import org.eclipse.jetty.annotations.ClassNameResolver;
27  import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
28  import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
29  import org.eclipse.jetty.util.resource.Resource;
30  import org.eclipse.jetty.webapp.DiscoveredAnnotation;
31  import org.eclipse.jetty.webapp.WebAppContext;
32  import org.osgi.framework.Bundle;
33  import org.osgi.framework.Constants;
34  
35  /**
36   * Extend the AnnotationConfiguration to support OSGi:
37   * Look for annotations inside WEB-INF/lib and also in the fragments and required bundles.
38   * Discover them using a scanner adapted to OSGi instead of the jarscanner. 
39   */
40  public class AnnotationConfiguration extends org.eclipse.jetty.annotations.AnnotationConfiguration
41  {
42  
43      /**
44       * This parser scans the bundles using the OSGi APIs instead of assuming a jar.
45       */
46      @Override
47      protected org.eclipse.jetty.annotations.AnnotationParser createAnnotationParser()
48      {
49          return new AnnotationParser();
50      }
51      
52      /**
53       * Here is the order in which jars and osgi artifacts are scanned for discoverable annotations.
54       * <ol>
55       * <li>The container jars are scanned.</li>
56       * <li>The WEB-INF/classes are scanned</li>
57       * <li>The osgi fragment to the web bundle are parsed.</li>
58       * <li>The WEB-INF/lib are scanned</li>
59       * <li>The required bundles are parsed</li>
60       * </ol>
61       */
62      @Override
63      public void parseWebInfLib (WebAppContext context, org.eclipse.jetty.annotations.AnnotationParser parser)
64      throws Exception
65      {
66          AnnotationParser oparser = (AnnotationParser)parser;
67          
68          Bundle webbundle = (Bundle) context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
69          Bundle[] fragAndRequiredBundles = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles(webbundle);
70          if (fragAndRequiredBundles != null)
71          {
72              //index:
73              for (Bundle bundle : fragAndRequiredBundles)
74              {
75                  Resource bundleRes = oparser.indexBundle(bundle);
76                  if (!context.getMetaData().getWebInfJars().contains(bundleRes))
77                  {
78                      context.getMetaData().addWebInfJar(bundleRes);
79                  }
80              }
81          
82              //scan the fragments
83              for (Bundle fragmentBundle : fragAndRequiredBundles)
84              {
85                  if (fragmentBundle.getHeaders().get(Constants.FRAGMENT_HOST) != null)
86                  {
87                      //a fragment indeed:
88                      parseFragmentBundle(context,oparser,webbundle,fragmentBundle);
89                  }
90              }
91          }
92          //scan ourselves
93          parseWebBundle(context,oparser,webbundle);
94          
95          //scan the WEB-INF/lib
96          super.parseWebInfLib(context,parser);
97          if (fragAndRequiredBundles != null)
98          {
99              //scan the required bundles
100             for (Bundle requiredBundle : fragAndRequiredBundles)
101             {
102                 if (requiredBundle.getHeaders().get(Constants.FRAGMENT_HOST) == null)
103                 {
104                     //a bundle indeed:
105                     parseRequiredBundle(context,oparser,webbundle,requiredBundle);
106                 }
107             }
108         }
109     }
110     
111     /**
112      * Scan a fragment bundle for servlet annotations
113      * @param context The webapp context
114      * @param parser The parser
115      * @param webbundle The current webbundle
116      * @param fragmentBundle The OSGi fragment bundle to scan
117      * @throws Exception
118      */
119     protected void parseFragmentBundle(WebAppContext context, AnnotationParser parser,
120             Bundle webbundle, Bundle fragmentBundle) throws Exception
121     {
122         parseBundle(context,parser,webbundle,fragmentBundle);
123     }
124     
125     /**
126      * Scan a bundle required by the webbundle for servlet annotations
127      * @param context The webapp context
128      * @param parser The parser
129      * @param webbundle The current webbundle
130      * @param fragmentBundle The OSGi required bundle to scan
131      * @throws Exception
132      */
133     protected void parseWebBundle(WebAppContext context, AnnotationParser parser, Bundle webbundle)
134     throws Exception
135     {
136         parseBundle(context,parser,webbundle,webbundle);
137     }
138     
139     /**
140      * Scan a bundle required by the webbundle for servlet annotations
141      * @param context The webapp context
142      * @param parser The parser
143      * @param webbundle The current webbundle
144      * @param fragmentBundle The OSGi required bundle to scan
145      * @throws Exception
146      */
147     protected void parseRequiredBundle(WebAppContext context, AnnotationParser parser,
148             Bundle webbundle, Bundle requiredBundle) throws Exception
149     {
150         parseBundle(context,parser,webbundle,requiredBundle);
151     }
152     
153     protected void parseBundle(WebAppContext context, AnnotationParser parser,
154             Bundle webbundle, Bundle bundle) throws Exception
155     {
156         
157         Resource bundleRes = parser.getResource(bundle);
158         
159         parser.clearHandlers();
160         for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
161         {
162             if (h instanceof AbstractDiscoverableAnnotationHandler)
163             {
164                 if (webbundle == bundle)                    
165                 ((AbstractDiscoverableAnnotationHandler)h).setResource(null); 
166                 else
167                     ((AbstractDiscoverableAnnotationHandler)h).setResource(bundleRes);  
168             }
169         }
170         parser.registerHandlers(_discoverableAnnotationHandlers);
171         parser.registerHandler(_classInheritanceHandler);
172         parser.registerHandlers(_containerInitializerAnnotationHandlers);
173       
174         parser.parse(bundle,createClassNameResolver(context));
175     }
176     
177     /**
178      * Returns the same classname resolver than for the webInfjar scanner
179      * @param context
180      * @return
181      */
182     protected ClassNameResolver createClassNameResolver(final WebAppContext context)
183     {
184         return createClassNameResolver(context,true,false,false,false);
185     }
186     
187     protected ClassNameResolver createClassNameResolver(final WebAppContext context,
188             final boolean excludeSysClass, final boolean excludeServerClass, final boolean excludeEverythingElse,
189             final boolean overrideIsParenLoaderIsPriority)
190     {
191         return new ClassNameResolver ()
192         {
193             public boolean isExcluded (String name)
194             {
195                 if (context.isSystemClass(name)) return excludeSysClass;
196                 if (context.isServerClass(name)) return excludeServerClass;
197                 return excludeEverythingElse;
198             }
199 
200             public boolean shouldOverride (String name)
201             { 
202                 //looking at system classpath
203                 if (context.isParentLoaderPriority())
204                     return overrideIsParenLoaderIsPriority;
205                 return !overrideIsParenLoaderIsPriority;
206             }
207         };
208     }
209 
210 }