View Javadoc

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