View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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                 //skip bundles that have been uninstalled since we discovered them
107                 if (bundle.getState() == Bundle.UNINSTALLED)
108                     continue;
109                 
110                 Resource bundleRes = oparser.indexBundle(bundle);
111                 if (!context.getMetaData().getWebInfJars().contains(bundleRes))
112                 {
113                     context.getMetaData().addWebInfJar(bundleRes);
114                 }
115                 
116                 if (bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null)
117                 {
118                     //a fragment indeed:
119                     parseFragmentBundle(context,oparser,webbundle,bundle);
120                 }
121             }
122         }
123         //scan ourselves
124         oparser.indexBundle(webbundle);
125         parseWebBundle(context,oparser,webbundle);
126         
127         //scan the WEB-INF/lib
128         super.parseWebInfLib(context,parser);
129         if (fragAndRequiredBundles != null)
130         {
131             //scan the required bundles
132             for (Bundle requiredBundle : fragAndRequiredBundles)
133             {
134                 //skip bundles that have been uninstalled since we discovered them
135                 if (requiredBundle.getState() == Bundle.UNINSTALLED)
136                     continue;
137                 
138                 if (requiredBundle.getHeaders().get(Constants.FRAGMENT_HOST) == null)
139                 {
140                     //a bundle indeed:
141                     parseRequiredBundle(context,oparser,webbundle,requiredBundle);
142                 }
143             }
144         }
145     }
146     
147     /**
148      * Scan a fragment bundle for servlet annotations
149      * @param context The webapp context
150      * @param parser The parser
151      * @param webbundle The current webbundle
152      * @param fragmentBundle The OSGi fragment bundle to scan
153      * @throws Exception
154      */
155     protected void parseFragmentBundle(WebAppContext context, AnnotationParser parser,
156             Bundle webbundle, Bundle fragmentBundle) throws Exception
157     {
158         parseBundle(context,parser,webbundle,fragmentBundle);
159     }
160     
161     /**
162      * Scan a bundle required by the webbundle for servlet annotations
163      * @param context The webapp context
164      * @param parser The parser
165      * @param webbundle The current webbundle
166      * @param fragmentBundle The OSGi required bundle to scan
167      * @throws Exception
168      */
169     protected void parseWebBundle(WebAppContext context, AnnotationParser parser, Bundle webbundle)
170     throws Exception
171     {
172         parseBundle(context,parser,webbundle,webbundle);
173     }
174     
175     /**
176      * Scan a bundle required by the webbundle for servlet annotations
177      * @param context The webapp context
178      * @param parser The parser
179      * @param webbundle The current webbundle
180      * @param fragmentBundle The OSGi required bundle to scan
181      * @throws Exception
182      */
183     protected void parseRequiredBundle(WebAppContext context, AnnotationParser parser,
184             Bundle webbundle, Bundle requiredBundle) throws Exception
185     {
186         parseBundle(context,parser,webbundle,requiredBundle);
187     }
188     
189     protected void parseBundle(WebAppContext context, AnnotationParser parser,
190                                Bundle webbundle, Bundle bundle) throws Exception
191                                {
192 
193         Resource bundleRes = parser.getResource(bundle);  
194         Set<Handler> handlers = new HashSet<Handler>();
195         handlers.addAll(_discoverableAnnotationHandlers);
196         if (_classInheritanceHandler != null)
197             handlers.add(_classInheritanceHandler);
198         handlers.addAll(_containerInitializerAnnotationHandlers);
199 
200         ClassNameResolver classNameResolver = createClassNameResolver(context);
201         if (_parserTasks != null)
202         {
203             BundleParserTask task = new BundleParserTask(parser, handlers, bundleRes, classNameResolver);
204             _parserTasks.add(task);
205             if (LOG.isDebugEnabled())
206                 task.setStatistic(new TimeStatistic());
207         }
208     }
209     
210     /**
211      * Returns the same classname resolver than for the webInfjar scanner
212      * @param context
213      * @return
214      */
215     protected ClassNameResolver createClassNameResolver(final WebAppContext context)
216     {
217         return createClassNameResolver(context,true,false,false,false);
218     }
219     
220     protected ClassNameResolver createClassNameResolver(final WebAppContext context,
221             final boolean excludeSysClass, final boolean excludeServerClass, final boolean excludeEverythingElse,
222             final boolean overrideIsParenLoaderIsPriority)
223     {
224         return new ClassNameResolver ()
225         {
226             public boolean isExcluded (String name)
227             {
228                 if (context.isSystemClass(name)) return excludeSysClass;
229                 if (context.isServerClass(name)) return excludeServerClass;
230                 return excludeEverythingElse;
231             }
232 
233             public boolean shouldOverride (String name)
234             { 
235                 //looking at system classpath
236                 if (context.isParentLoaderPriority())
237                     return overrideIsParenLoaderIsPriority;
238                 return !overrideIsParenLoaderIsPriority;
239             }
240         };
241     }
242 
243 }