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