| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 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.boot; |
| |
| import java.util.Dictionary; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.Map; |
| |
| import org.eclipse.jetty.deploy.App; |
| import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper; |
| import org.eclipse.jetty.osgi.boot.utils.Util; |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.FrameworkUtil; |
| import org.osgi.framework.ServiceRegistration; |
| |
| /** |
| * BundleWebAppProvider |
| * <p> |
| * A Jetty Provider that knows how to deploy a WebApp contained inside a Bundle. |
| */ |
| public class BundleWebAppProvider extends AbstractWebAppProvider implements BundleProvider |
| { |
| private static final Logger LOG = Log.getLogger(AbstractWebAppProvider.class); |
| |
| /** |
| * Map of Bundle to App. Used when a Bundle contains a webapp. |
| */ |
| private Map<Bundle, App> _bundleMap = new HashMap<Bundle, App>(); |
| |
| private ServiceRegistration _serviceRegForBundles; |
| |
| |
| /* ------------------------------------------------------------ */ |
| public BundleWebAppProvider (ServerInstanceWrapper wrapper) |
| { |
| super(wrapper); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart() |
| */ |
| protected void doStart() throws Exception |
| { |
| //register as an osgi service for deploying bundles, advertising the name of the jetty Server instance we are related to |
| Dictionary<String,String> properties = new Hashtable<String,String>(); |
| properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, getServerInstanceWrapper().getManagedServerName()); |
| _serviceRegForBundles = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(BundleProvider.class.getName(), this, properties); |
| super.doStart(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop() |
| */ |
| @Override |
| protected void doStop() throws Exception |
| { |
| //unregister ourselves |
| if (_serviceRegForBundles != null) |
| { |
| try |
| { |
| _serviceRegForBundles.unregister(); |
| } |
| catch (Exception e) |
| { |
| LOG.warn(e); |
| } |
| } |
| |
| super.doStop(); |
| } |
| |
| |
| |
| |
| |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * A bundle has been added that could be a webapp |
| * @param bundle the bundle |
| */ |
| public boolean bundleAdded (Bundle bundle) throws Exception |
| { |
| if (bundle == null) |
| return false; |
| |
| ClassLoader cl = Thread.currentThread().getContextClassLoader(); |
| Thread.currentThread().setContextClassLoader(getServerInstanceWrapper().getParentClassLoaderForWebapps()); |
| String contextPath = null; |
| try |
| { |
| Dictionary headers = bundle.getHeaders(); |
| |
| //does the bundle have a OSGiWebappConstants.JETTY_WAR_FOLDER_PATH |
| String resourcePath = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH, OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH, headers); |
| if (resourcePath != null) |
| { |
| String base = resourcePath; |
| contextPath = getContextPath(bundle); |
| String originId = getOriginId(bundle, base); |
| |
| //TODO : we don't know whether an app is actually deployed, as deploymentManager swallows all |
| //exceptions inside the impl of addApp. Need to send the Event and also register as a service |
| //only if the deployment succeeded |
| OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId); |
| app.setWebAppPath(base); |
| app.setContextPath(contextPath); |
| _bundleMap.put(bundle, app); |
| getDeploymentManager().addApp(app); |
| return true; |
| } |
| |
| |
| //does the bundle have a WEB-INF/web.xml |
| if (bundle.getEntry("/WEB-INF/web.xml") != null) |
| { |
| String base = "."; |
| contextPath = getContextPath(bundle); |
| String originId = getOriginId(bundle, base); |
| |
| OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId); |
| app.setContextPath(contextPath); |
| app.setWebAppPath(base); |
| _bundleMap.put(bundle, app); |
| getDeploymentManager().addApp(app); |
| return true; |
| } |
| |
| //does the bundle define a OSGiWebappConstants.RFC66_WEB_CONTEXTPATH |
| if (headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH) != null) |
| { |
| //Could be a static webapp with no web.xml |
| String base = "."; |
| contextPath = (String)headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); |
| String originId = getOriginId(bundle,base); |
| |
| OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId); |
| app.setContextPath(contextPath); |
| app.setWebAppPath(base); |
| _bundleMap.put(bundle, app); |
| getDeploymentManager().addApp(app); |
| return true; |
| } |
| |
| return false; |
| } |
| catch (Exception e) |
| { |
| |
| throw e; |
| } |
| finally |
| { |
| Thread.currentThread().setContextClassLoader(cl); |
| } |
| } |
| |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Bundle has been removed. If it was a webapp we deployed, undeploy it. |
| * |
| * @param bundle the bundle |
| * @return true if this was a webapp we had deployed, false otherwise |
| */ |
| public boolean bundleRemoved (Bundle bundle) throws Exception |
| { |
| App app = _bundleMap.remove(bundle); |
| if (app != null) |
| { |
| getDeploymentManager().removeApp(app); |
| return true; |
| } |
| return false; |
| } |
| |
| |
| |
| |
| |
| /* ------------------------------------------------------------ */ |
| private static String getContextPath(Bundle bundle) |
| { |
| Dictionary<?, ?> headers = bundle.getHeaders(); |
| String contextPath = (String) headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); |
| if (contextPath == null) |
| { |
| // extract from the last token of the bundle's location: |
| // (really ?could consider processing the symbolic name as an alternative |
| // the location will often reflect the version. |
| // maybe this is relevant when the file is a war) |
| String location = bundle.getLocation(); |
| String toks[] = location.replace('\\', '/').split("/"); |
| contextPath = toks[toks.length - 1]; |
| // remove .jar, .war etc: |
| int lastDot = contextPath.lastIndexOf('.'); |
| if (lastDot != -1) |
| contextPath = contextPath.substring(0, lastDot); |
| } |
| if (!contextPath.startsWith("/")) |
| contextPath = "/" + contextPath; |
| |
| return contextPath; |
| } |
| |
| |
| |
| } |