| // |
| // ======================================================================== |
| // 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.io.File; |
| import java.net.URL; |
| import java.util.Dictionary; |
| import java.util.HashMap; |
| |
| import org.eclipse.jetty.deploy.App; |
| import org.eclipse.jetty.deploy.AppProvider; |
| import org.eclipse.jetty.deploy.DeploymentManager; |
| import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper; |
| import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory; |
| import org.eclipse.jetty.osgi.boot.utils.OSGiClassLoader; |
| import org.eclipse.jetty.server.handler.ContextHandler; |
| import org.eclipse.jetty.util.component.AbstractLifeCycle; |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| import org.eclipse.jetty.util.resource.JarResource; |
| import org.eclipse.jetty.util.resource.Resource; |
| import org.eclipse.jetty.xml.XmlConfiguration; |
| import org.osgi.framework.Bundle; |
| |
| |
| |
| |
| /** |
| * AbstractContextProvider |
| * |
| * Base class for DeploymentManager Providers that can deploy ContextHandlers into |
| * Jetty that have been discovered via OSGI either as bundles or services. |
| * |
| */ |
| public abstract class AbstractContextProvider extends AbstractLifeCycle implements AppProvider |
| { |
| private static final Logger LOG = Log.getLogger(AbstractContextProvider.class); |
| |
| private DeploymentManager _deploymentManager; |
| |
| private ServerInstanceWrapper _serverWrapper; |
| |
| |
| |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * OSGiApp |
| * |
| * |
| */ |
| public class OSGiApp extends AbstractOSGiApp |
| { |
| private String _contextFile; |
| private ContextHandler _contextHandler; |
| private boolean _configured = false; |
| |
| public OSGiApp(DeploymentManager manager, AppProvider provider, String originId, Bundle bundle, String contextFile) |
| { |
| super(manager, provider, bundle, originId); |
| _contextFile = contextFile; |
| } |
| |
| public OSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String contextFile, String originId) |
| { |
| super(manager, provider, bundle, properties, originId); |
| _contextFile = contextFile; |
| } |
| |
| public String getContextFile () |
| { |
| return _contextFile; |
| } |
| |
| public void setHandler(ContextHandler h) |
| { |
| _contextHandler = h; |
| } |
| |
| public ContextHandler createContextHandler() |
| throws Exception |
| { |
| configureContextHandler(); |
| return _contextHandler; |
| } |
| |
| public void configureContextHandler() |
| throws Exception |
| { |
| if (_configured) |
| return; |
| |
| _configured = true; |
| |
| //Override for bundle root may have been set |
| String bundleOverrideLocation = (String)_properties.get(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE); |
| if (bundleOverrideLocation == null) |
| bundleOverrideLocation = (String)_properties.get(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE); |
| |
| //Location on filesystem of bundle or the bundle override location |
| File bundleLocation = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(_bundle); |
| File root = (bundleOverrideLocation==null?bundleLocation:new File(bundleOverrideLocation)); |
| Resource rootResource = Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(root.toURI().toURL())); |
| |
| //try and make sure the rootResource is useable - if its a jar then make it a jar file url |
| if (rootResource.exists()&& !rootResource.isDirectory() && !rootResource.toString().startsWith("jar:")) |
| { |
| Resource jarResource = JarResource.newJarResource(rootResource); |
| if (jarResource.exists() && jarResource.isDirectory()) |
| rootResource = jarResource; |
| } |
| |
| //Set the base resource of the ContextHandler, if not already set, can also be overridden by the context xml file |
| if (_contextHandler != null && _contextHandler.getBaseResource() == null) |
| { |
| _contextHandler.setBaseResource(rootResource); |
| } |
| |
| //Use a classloader that knows about the common jetty parent loader, and also the bundle |
| OSGiClassLoader classLoader = new OSGiClassLoader(getServerInstanceWrapper().getParentClassLoaderForWebapps(), _bundle); |
| |
| //if there is a context file, find it and apply it |
| if (_contextFile == null && _contextHandler == null) |
| throw new IllegalStateException("No context file or ContextHandler"); |
| |
| if (_contextFile != null) |
| { |
| //apply the contextFile, creating the ContextHandler, the DeploymentManager will register it in the ContextHandlerCollection |
| Resource res = null; |
| |
| String jettyHome = (String)getServerInstanceWrapper().getServer().getAttribute(OSGiServerConstants.JETTY_HOME); |
| if (jettyHome == null) |
| jettyHome = System.getProperty(OSGiServerConstants.JETTY_HOME); |
| |
| res = findFile(_contextFile, jettyHome, bundleOverrideLocation, _bundle); |
| |
| //apply the context xml file, either to an existing ContextHandler, or letting the |
| //it create the ContextHandler as necessary |
| if (res != null) |
| { |
| ClassLoader cl = Thread.currentThread().getContextClassLoader(); |
| |
| LOG.debug("Context classloader = " + cl); |
| try |
| { |
| Thread.currentThread().setContextClassLoader(classLoader); |
| |
| XmlConfiguration xmlConfiguration = new XmlConfiguration(res.getInputStream()); |
| HashMap properties = new HashMap(); |
| //put the server instance in |
| properties.put("Server", getServerInstanceWrapper().getServer()); |
| //put in the location of the bundle root |
| properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString()); |
| |
| // insert the bundle's location as a property. |
| xmlConfiguration.getProperties().putAll(properties); |
| |
| if (_contextHandler == null) |
| _contextHandler = (ContextHandler) xmlConfiguration.configure(); |
| else |
| xmlConfiguration.configure(_contextHandler); |
| } |
| finally |
| { |
| Thread.currentThread().setContextClassLoader(cl); |
| } |
| } |
| } |
| |
| //Set up the class loader we created |
| _contextHandler.setClassLoader(classLoader); |
| |
| |
| //If a bundle/service property specifies context path, let it override the context xml |
| String contextPath = (String)_properties.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); |
| if (contextPath == null) |
| contextPath = (String)_properties.get(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH); |
| if (contextPath != null) |
| _contextHandler.setContextPath(contextPath); |
| |
| //osgi Enterprise Spec r4 p.427 |
| _contextHandler.setAttribute(OSGiWebappConstants.OSGI_BUNDLECONTEXT, _bundle.getBundleContext()); |
| |
| //make sure we protect also the osgi dirs specified by OSGi Enterprise spec |
| String[] targets = _contextHandler.getProtectedTargets(); |
| int length = (targets==null?0:targets.length); |
| |
| String[] updatedTargets = null; |
| if (targets != null) |
| { |
| updatedTargets = new String[length+OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length]; |
| System.arraycopy(targets, 0, updatedTargets, 0, length); |
| |
| } |
| else |
| updatedTargets = new String[OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length]; |
| System.arraycopy(OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS, 0, updatedTargets, length, OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length); |
| _contextHandler.setProtectedTargets(updatedTargets); |
| |
| } |
| |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public AbstractContextProvider(ServerInstanceWrapper wrapper) |
| { |
| _serverWrapper = wrapper; |
| } |
| |
| |
| /* ------------------------------------------------------------ */ |
| public ServerInstanceWrapper getServerInstanceWrapper() |
| { |
| return _serverWrapper; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.deploy.AppProvider#createContextHandler(org.eclipse.jetty.deploy.App) |
| */ |
| public ContextHandler createContextHandler(App app) throws Exception |
| { |
| if (app == null) |
| return null; |
| if (!(app instanceof OSGiApp)) |
| throw new IllegalStateException(app+" is not a BundleApp"); |
| |
| //Create a ContextHandler suitable to deploy in OSGi |
| ContextHandler h = ((OSGiApp)app).createContextHandler(); |
| return h; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void setDeploymentManager(DeploymentManager deploymentManager) |
| { |
| _deploymentManager = deploymentManager; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public DeploymentManager getDeploymentManager() |
| { |
| return _deploymentManager; |
| } |
| } |