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.HashSet;
22  import java.util.Set;
23  
24  import org.eclipse.jetty.annotations.AnnotationParser.Handler;
25  import org.eclipse.jetty.annotations.ClassNameResolver;
26  import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
27  import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
28  import org.eclipse.jetty.util.resource.Resource;
29  import org.eclipse.jetty.webapp.WebAppContext;
30  import org.osgi.framework.Bundle;
31  import org.osgi.framework.Constants;
32  
33  /**
34   * Extend the AnnotationConfiguration to support OSGi:
35   * Look for annotations inside WEB-INF/lib and also in the fragments and required bundles.
36   * Discover them using a scanner adapted to OSGi instead of the jarscanner. 
37   */
38  public class AnnotationConfiguration extends org.eclipse.jetty.annotations.AnnotationConfiguration
39  {
40      public class BundleParserTask extends ParserTask
41      {
42          
43          public BundleParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource, ClassNameResolver resolver)
44          {
45             super(parser, handlers, resource, resolver);
46          }
47  
48          public Void call() throws Exception
49          {
50              if (_parser != null)
51              {
52                  org.eclipse.jetty.osgi.annotations.AnnotationParser osgiAnnotationParser = (org.eclipse.jetty.osgi.annotations.AnnotationParser)_parser;
53                  Bundle bundle = osgiAnnotationParser.getBundle(_resource);
54                  osgiAnnotationParser.parse(_handlers, bundle,  _resolver); 
55              }
56              return null;
57          }
58      }
59      
60      
61      /**
62       * This parser scans the bundles using the OSGi APIs instead of assuming a jar.
63       */
64      @Override
65      protected org.eclipse.jetty.annotations.AnnotationParser createAnnotationParser()
66      {
67          return new AnnotationParser();
68      }
69      
70      /**
71       * Here is the order in which jars and osgi artifacts are scanned for discoverable annotations.
72       * <ol>
73       * <li>The container jars are scanned.</li>
74       * <li>The WEB-INF/classes are scanned</li>
75       * <li>The osgi fragment to the web bundle are parsed.</li>
76       * <li>The WEB-INF/lib are scanned</li>
77       * <li>The required bundles are parsed</li>
78       * </ol>
79       */
80      @Override
81      public void parseWebInfLib (WebAppContext context, org.eclipse.jetty.annotations.AnnotationParser parser)
82      throws Exception
83      {
84          AnnotationParser oparser = (AnnotationParser)parser;
85          
86          Bundle webbundle = (Bundle) context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
87          Bundle[] fragAndRequiredBundles = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles(webbundle);
88          if (fragAndRequiredBundles != null)
89          {
90              //index and scan fragments
91              for (Bundle bundle : fragAndRequiredBundles)
92              {
93                  Resource bundleRes = oparser.indexBundle(bundle);
94                  if (!context.getMetaData().getWebInfJars().contains(bundleRes))
95                  {
96                      context.getMetaData().addWebInfJar(bundleRes);
97                  }
98                  
99                  if (bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null)
100                 {
101                     //a fragment indeed:
102                     parseFragmentBundle(context,oparser,webbundle,bundle);
103                 }
104             }
105         }
106         //scan ourselves
107         oparser.indexBundle(webbundle);
108         parseWebBundle(context,oparser,webbundle);
109         
110         //scan the WEB-INF/lib
111         super.parseWebInfLib(context,parser);
112         if (fragAndRequiredBundles != null)
113         {
114             //scan the required bundles
115             for (Bundle requiredBundle : fragAndRequiredBundles)
116             {
117                 if (requiredBundle.getHeaders().get(Constants.FRAGMENT_HOST) == null)
118                 {
119                     //a bundle indeed:
120                     parseRequiredBundle(context,oparser,webbundle,requiredBundle);
121                 }
122             }
123         }
124     }
125     
126     /**
127      * Scan a fragment bundle for servlet annotations
128      * @param context The webapp context
129      * @param parser The parser
130      * @param webbundle The current webbundle
131      * @param fragmentBundle The OSGi fragment bundle to scan
132      * @throws Exception
133      */
134     protected void parseFragmentBundle(WebAppContext context, AnnotationParser parser,
135             Bundle webbundle, Bundle fragmentBundle) throws Exception
136     {
137         parseBundle(context,parser,webbundle,fragmentBundle);
138     }
139     
140     /**
141      * Scan a bundle required by the webbundle for servlet annotations
142      * @param context The webapp context
143      * @param parser The parser
144      * @param webbundle The current webbundle
145      * @param fragmentBundle The OSGi required bundle to scan
146      * @throws Exception
147      */
148     protected void parseWebBundle(WebAppContext context, AnnotationParser parser, Bundle webbundle)
149     throws Exception
150     {
151         parseBundle(context,parser,webbundle,webbundle);
152     }
153     
154     /**
155      * Scan a bundle required by the webbundle for servlet annotations
156      * @param context The webapp context
157      * @param parser The parser
158      * @param webbundle The current webbundle
159      * @param fragmentBundle The OSGi required bundle to scan
160      * @throws Exception
161      */
162     protected void parseRequiredBundle(WebAppContext context, AnnotationParser parser,
163             Bundle webbundle, Bundle requiredBundle) throws Exception
164     {
165         parseBundle(context,parser,webbundle,requiredBundle);
166     }
167     
168     protected void parseBundle(WebAppContext context, AnnotationParser parser,
169                                Bundle webbundle, Bundle bundle) throws Exception
170                                {
171 
172         Resource bundleRes = parser.getResource(bundle);  
173         Set<Handler> handlers = new HashSet<Handler>();
174         handlers.addAll(_discoverableAnnotationHandlers);
175         if (_classInheritanceHandler != null)
176             handlers.add(_classInheritanceHandler);
177         handlers.addAll(_containerInitializerAnnotationHandlers);
178 
179         ClassNameResolver classNameResolver = createClassNameResolver(context);
180         if (_parserTasks != null)
181             _parserTasks.add(new BundleParserTask(parser, handlers, bundleRes, classNameResolver));
182     }
183     
184     /**
185      * Returns the same classname resolver than for the webInfjar scanner
186      * @param context
187      * @return
188      */
189     protected ClassNameResolver createClassNameResolver(final WebAppContext context)
190     {
191         return createClassNameResolver(context,true,false,false,false);
192     }
193     
194     protected ClassNameResolver createClassNameResolver(final WebAppContext context,
195             final boolean excludeSysClass, final boolean excludeServerClass, final boolean excludeEverythingElse,
196             final boolean overrideIsParenLoaderIsPriority)
197     {
198         return new ClassNameResolver ()
199         {
200             public boolean isExcluded (String name)
201             {
202                 if (context.isSystemClass(name)) return excludeSysClass;
203                 if (context.isServerClass(name)) return excludeServerClass;
204                 return excludeEverythingElse;
205             }
206 
207             public boolean shouldOverride (String name)
208             { 
209                 //looking at system classpath
210                 if (context.isParentLoaderPriority())
211                     return overrideIsParenLoaderIsPriority;
212                 return !overrideIsParenLoaderIsPriority;
213             }
214         };
215     }
216 
217 }