// // ======================================================================== // 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.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; } }