| // |
| // ======================================================================== |
| // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.osgi.annotations; |
| |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| import org.eclipse.jetty.annotations.AnnotationParser.Handler; |
| import org.eclipse.jetty.annotations.ClassNameResolver; |
| import org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration; |
| import org.eclipse.jetty.osgi.boot.OSGiWebappConstants; |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| import org.eclipse.jetty.util.resource.Resource; |
| import org.eclipse.jetty.webapp.WebAppContext; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.Constants; |
| |
| /** |
| * Extend the AnnotationConfiguration to support OSGi: |
| * Look for annotations inside WEB-INF/lib and also in the fragments and required bundles. |
| * Discover them using a scanner adapted to OSGi instead of the jarscanner. |
| */ |
| public class AnnotationConfiguration extends org.eclipse.jetty.annotations.AnnotationConfiguration |
| { |
| private static final Logger LOG = Log.getLogger(org.eclipse.jetty.annotations.AnnotationConfiguration.class); |
| |
| public class BundleParserTask extends ParserTask |
| { |
| |
| public BundleParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource, ClassNameResolver resolver) |
| { |
| super(parser, handlers, resource, resolver); |
| } |
| |
| public Void call() throws Exception |
| { |
| if (_parser != null) |
| { |
| org.eclipse.jetty.osgi.annotations.AnnotationParser osgiAnnotationParser = (org.eclipse.jetty.osgi.annotations.AnnotationParser)_parser; |
| Bundle bundle = osgiAnnotationParser.getBundle(_resource); |
| if (_stat != null) |
| _stat.start(); |
| osgiAnnotationParser.parse(_handlers, bundle, _resolver); |
| if (_stat != null) |
| _stat.end(); |
| } |
| return null; |
| } |
| } |
| |
| |
| public AnnotationConfiguration() |
| { |
| } |
| |
| /** |
| * This parser scans the bundles using the OSGi APIs instead of assuming a jar. |
| */ |
| @Override |
| protected org.eclipse.jetty.annotations.AnnotationParser createAnnotationParser() |
| { |
| return new AnnotationParser(); |
| } |
| |
| /** |
| * Here is the order in which jars and osgi artifacts are scanned for discoverable annotations. |
| * <ol> |
| * <li>The container jars are scanned.</li> |
| * <li>The WEB-INF/classes are scanned</li> |
| * <li>The osgi fragment to the web bundle are parsed.</li> |
| * <li>The WEB-INF/lib are scanned</li> |
| * <li>The required bundles are parsed</li> |
| * </ol> |
| */ |
| @Override |
| public void parseWebInfLib (WebAppContext context, org.eclipse.jetty.annotations.AnnotationParser parser) |
| throws Exception |
| { |
| AnnotationParser oparser = (AnnotationParser)parser; |
| |
| Bundle webbundle = (Bundle) context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE); |
| Set<Bundle> fragAndRequiredBundles = (Set<Bundle>)context.getAttribute(OSGiWebInfConfiguration.FRAGMENT_AND_REQUIRED_BUNDLES); |
| if (fragAndRequiredBundles != null) |
| { |
| //index and scan fragments |
| for (Bundle bundle : fragAndRequiredBundles) |
| { |
| //skip bundles that have been uninstalled since we discovered them |
| if (bundle.getState() == Bundle.UNINSTALLED) |
| continue; |
| |
| Resource bundleRes = oparser.indexBundle(bundle); |
| if (!context.getMetaData().getWebInfJars().contains(bundleRes)) |
| { |
| context.getMetaData().addWebInfJar(bundleRes); |
| } |
| |
| if (bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null) |
| { |
| //a fragment indeed: |
| parseFragmentBundle(context,oparser,webbundle,bundle); |
| } |
| } |
| } |
| //scan ourselves |
| oparser.indexBundle(webbundle); |
| parseWebBundle(context,oparser,webbundle); |
| |
| //scan the WEB-INF/lib |
| super.parseWebInfLib(context,parser); |
| if (fragAndRequiredBundles != null) |
| { |
| //scan the required bundles |
| for (Bundle requiredBundle : fragAndRequiredBundles) |
| { |
| //skip bundles that have been uninstalled since we discovered them |
| if (requiredBundle.getState() == Bundle.UNINSTALLED) |
| continue; |
| |
| if (requiredBundle.getHeaders().get(Constants.FRAGMENT_HOST) == null) |
| { |
| //a bundle indeed: |
| parseRequiredBundle(context,oparser,webbundle,requiredBundle); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Scan a fragment bundle for servlet annotations |
| * @param context The webapp context |
| * @param parser The parser |
| * @param webbundle The current webbundle |
| * @param fragmentBundle The OSGi fragment bundle to scan |
| * @throws Exception if unable to parse fragment bundle |
| */ |
| protected void parseFragmentBundle(WebAppContext context, AnnotationParser parser, |
| Bundle webbundle, Bundle fragmentBundle) throws Exception |
| { |
| parseBundle(context,parser,webbundle,fragmentBundle); |
| } |
| |
| /** |
| * Scan a bundle required by the webbundle for servlet annotations |
| * @param context The webapp context |
| * @param parser The parser |
| * @param webbundle The current webbundle |
| * @throws Exception if unable to parse the web bundle |
| */ |
| protected void parseWebBundle(WebAppContext context, AnnotationParser parser, Bundle webbundle) |
| throws Exception |
| { |
| parseBundle(context,parser,webbundle,webbundle); |
| } |
| |
| /** |
| * Scan a bundle required by the webbundle for servlet annotations |
| * @param context The webapp context |
| * @param parser The parser |
| * @param webbundle The current webbundle |
| * @param requiredBundle The OSGi required bundle to scan |
| * @throws Exception if unable to parse the required bundle |
| */ |
| protected void parseRequiredBundle(WebAppContext context, AnnotationParser parser, |
| Bundle webbundle, Bundle requiredBundle) throws Exception |
| { |
| parseBundle(context,parser,webbundle,requiredBundle); |
| } |
| |
| protected void parseBundle(WebAppContext context, AnnotationParser parser, |
| Bundle webbundle, Bundle bundle) throws Exception |
| { |
| |
| Resource bundleRes = parser.getResource(bundle); |
| Set<Handler> handlers = new HashSet<Handler>(); |
| handlers.addAll(_discoverableAnnotationHandlers); |
| if (_classInheritanceHandler != null) |
| handlers.add(_classInheritanceHandler); |
| handlers.addAll(_containerInitializerAnnotationHandlers); |
| |
| ClassNameResolver classNameResolver = createClassNameResolver(context); |
| if (_parserTasks != null) |
| { |
| BundleParserTask task = new BundleParserTask(parser, handlers, bundleRes, classNameResolver); |
| _parserTasks.add(task); |
| if (LOG.isDebugEnabled()) |
| task.setStatistic(new TimeStatistic()); |
| } |
| } |
| |
| /** |
| * Returns the same classname resolver than for the webInfjar scanner |
| * @param context the web app context |
| * @return the class name resolver |
| */ |
| protected ClassNameResolver createClassNameResolver(final WebAppContext context) |
| { |
| return createClassNameResolver(context,true,false,false,false); |
| } |
| |
| protected ClassNameResolver createClassNameResolver(final WebAppContext context, |
| final boolean excludeSysClass, final boolean excludeServerClass, final boolean excludeEverythingElse, |
| final boolean overrideIsParenLoaderIsPriority) |
| { |
| return new ClassNameResolver () |
| { |
| public boolean isExcluded (String name) |
| { |
| if (context.isSystemClass(name)) return excludeSysClass; |
| if (context.isServerClass(name)) return excludeServerClass; |
| return excludeEverythingElse; |
| } |
| |
| public boolean shouldOverride (String name) |
| { |
| //looking at system classpath |
| if (context.isParentLoaderPriority()) |
| return overrideIsParenLoaderIsPriority; |
| return !overrideIsParenLoaderIsPriority; |
| } |
| }; |
| } |
| |
| } |