View Javadoc

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