blob: 1a7525e3a147968fc904a013a1b9a489e9594e2b [file] [log] [blame]
//
// ========================================================================
// 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;
}
}