Refactoring

This commit is contained in:
Jan Bartel 2012-05-14 18:46:21 +02:00
parent 9773113a47
commit b2998c2c4d
33 changed files with 2078 additions and 1111 deletions

View File

@ -19,9 +19,13 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.osgi.boot.OSGiAppProvider;
import org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
import org.osgi.framework.Bundle;
@ -56,10 +60,10 @@ public class PluggableWebAppRegistrationCustomizerImpl implements WebappRegistra
* @param provider
* @return
*/
private static Collection<String> getTldBundles(OSGiAppProvider provider)
private static Collection<String> getTldBundles(DeploymentManager deploymentManager)
{
String sysprop = System.getProperty(SYS_PROP_TLD_BUNDLES);
String att = (String) provider.getTldBundles();
String att = (String) deploymentManager.getContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN);
if (sysprop == null && att == null) { return Collections.emptySet(); }
if (att == null)
{
@ -83,9 +87,8 @@ public class PluggableWebAppRegistrationCustomizerImpl implements WebappRegistra
* @return The location of the jars that contain tld files. Jasper will
* discover them.
*/
public URL[] getJarsWithTlds(OSGiAppProvider provider, BundleFileLocatorHelper locatorHelper) throws Exception
public URL[] getJarsWithTlds(DeploymentManager deploymentManager, BundleFileLocatorHelper locatorHelper) throws Exception
{
List<URL> urls = new ArrayList<URL>();
// naive way of finding those bundles.
// lots of assumptions: for example we assume a single version of each
// bundle that would contain tld files.
@ -96,13 +99,24 @@ public class PluggableWebAppRegistrationCustomizerImpl implements WebappRegistra
// and mirroring those in the MANIFEST.MF
Bundle[] bundles = FrameworkUtil.getBundle(PluggableWebAppRegistrationCustomizerImpl.class).getBundleContext().getBundles();
Collection<String> tldbundles = getTldBundles(provider);
HashSet<URL> urls = new HashSet<URL>();
String tmp = System.getProperty(SYS_PROP_TLD_BUNDLES); //comma separated exact names
List<String> sysNames = new ArrayList<String>();
if (tmp != null)
{
StringTokenizer tokenizer = new StringTokenizer(tmp, ", \n\r\t", false);
while (tokenizer.hasMoreTokens())
sysNames.add(tokenizer.nextToken());
}
tmp = (String) deploymentManager.getContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN); //bundle name patterns
Pattern pattern = (tmp==null? null : Pattern.compile(tmp));
for (Bundle bundle : bundles)
{
if (tldbundles.contains(bundle.getSymbolicName()))
{
if (sysNames.contains(bundle.getSymbolicName()))
registerTldBundle(locatorHelper, bundle, urls);
if (pattern != null && pattern.matcher(bundle.getSymbolicName()).matches())
registerTldBundle(locatorHelper, bundle, urls);
}
}
return urls.toArray(new URL[urls.size()]);
@ -134,7 +148,7 @@ public class PluggableWebAppRegistrationCustomizerImpl implements WebappRegistra
* @param urls
* @throws Exception
*/
private void registerTldBundle(BundleFileLocatorHelper locatorHelper, Bundle bundle, List<URL> urls) throws Exception
private void registerTldBundle(BundleFileLocatorHelper locatorHelper, Bundle bundle, Set<URL> urls) throws Exception
{
File jasperLocation = locatorHelper.getBundleInstallLocation(bundle);
if (jasperLocation.isDirectory())

View File

@ -25,10 +25,13 @@ import javax.servlet.jsp.JspFactory;
import org.apache.jasper.Constants;
import org.apache.jasper.compiler.Localizer;
import org.apache.jasper.xmlparser.ParserUtils;
import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
import org.eclipse.jetty.osgi.boot.OSGiAppProvider;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
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.xml.sax.EntityResolver;
@ -46,6 +49,8 @@ import org.xml.sax.SAXException;
*/
public class WebappRegistrationCustomizerImpl implements WebappRegistrationCustomizer
{
private static final Logger LOG = Log.getLogger(WebappRegistrationCustomizerImpl.class);
/**
* Default name of a class that belongs to the jstl bundle. From that class
@ -85,8 +90,7 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
}
catch (Exception e)
{
System.err.println("Unable to locate the JspServlet: jsp support unavailable.");
e.printStackTrace();
LOG.warn("Unable to locate the JspServlet: jsp support unavailable.", e);
return;
}
try
@ -106,8 +110,7 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
}
catch (Exception e)
{
System.err.println("Unable to set the JspFactory: jsp support incomplete.");
e.printStackTrace();
LOG.warn("Unable to set the JspFactory: jsp support incomplete.", e);
}
}
@ -129,7 +132,7 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
* @return array of URLs
* @throws Exception
*/
public URL[] getJarsWithTlds(OSGiAppProvider provider, BundleFileLocatorHelper locatorHelper) throws Exception
public URL[] getJarsWithTlds(DeploymentManager deployer, BundleFileLocatorHelper locatorHelper) throws Exception
{
HashSet<Class<?>> classesToAddToTheTldBundles = new HashSet<Class<?>>();

View File

@ -12,7 +12,9 @@
// ========================================================================
package org.eclipse.jetty.osgi.boot.jsp;
import org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleDeployerHelper;
import org.eclipse.jetty.osgi.boot.BundleWebAppProvider;
import org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleTrackerCustomizer;
import org.eclipse.jetty.osgi.boot.jasper.PluggableWebAppRegistrationCustomizerImpl;
import org.eclipse.jetty.osgi.boot.jasper.WebappRegistrationCustomizerImpl;
import org.osgi.framework.BundleActivator;
@ -24,7 +26,7 @@ import org.osgi.framework.BundleContext;
* called back by the host bundle.
* <p>
* It must be placed in the org.eclipse.jetty.osgi.boot.jsp package: this is
* because org.eclipse.jetty.osgi.boot.jsp is the sympbolic-name of this
* because org.eclipse.jetty.osgi.boot.jsp is the symbolic-name of this
* fragment. From that name, the PackageadminTracker will call this class. IN a
* different package it won't be called.
* </p>
@ -37,8 +39,11 @@ public class FragmentActivator implements BundleActivator
public void start(BundleContext context) throws Exception
{
System.setProperty("org.apache.jasper.compiler.disablejsr199", Boolean.TRUE.toString());
WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS.add(new WebappRegistrationCustomizerImpl());
WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS.add(new PluggableWebAppRegistrationCustomizerImpl());
WebBundleTrackerCustomizer.JSP_REGISTRATION_HELPERS.add(new WebappRegistrationCustomizerImpl());
WebBundleTrackerCustomizer.JSP_REGISTRATION_HELPERS.add(new PluggableWebAppRegistrationCustomizerImpl());
//Put in the support for the tag libs
addTagLibSupport();
}
/**
@ -48,4 +53,12 @@ public class FragmentActivator implements BundleActivator
{
}
public void addTagLibSupport ()
{
String[] defaultConfigurations = new String[BundleWebAppProvider.getDefaultConfigurations().length+1];
System.arraycopy(BundleWebAppProvider.getDefaultConfigurations(), 0, defaultConfigurations, 0, BundleWebAppProvider.getDefaultConfigurations().length);
defaultConfigurations[defaultConfigurations.length-1] = "org.eclipse.jetty.osgi.boot.jsp.TagLibOSGiConfiguration";
BundleWebAppProvider.setDefaultConfigurations(defaultConfigurations);
}
}

View File

@ -19,6 +19,7 @@ import java.util.Enumeration;
import java.util.LinkedHashSet;
import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.internal.DefaultFileLocatorHelper;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -108,7 +109,7 @@ public class TagLibOSGiConfiguration extends TagLibConfiguration
{
atLeastOneTldFound = true;
URL oriUrl = en.nextElement();
URL url = DefaultFileLocatorHelper.getLocalURL(oriUrl);
URL url = BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(oriUrl);
Resource tldResource;
try
{

View File

@ -17,22 +17,25 @@
<Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg>
</Call>
<!-- Providers of OSGi Apps -->
<Call name="addAppProvider">
<Arg>
<New class="org.eclipse.jetty.osgi.boot.OSGiAppProvider">
<!-- Call name="addAppProvider" -->
<!-- Arg -->
<!-- New class="org.eclipse.jetty.osgi.boot.OSGiAppProvider" -->
<!--
<Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set>
-->
<!--
<Set name="scanInterval">5</Set>
<Set name="contextXmlDir"><Property name="jetty.home" default="." />/contexts</Set>
-->
<!-- comma separated list of bundle symbolic names that contain custom tag libraries (*.tld files) -->
<!-- if those bundles don't exist or can't be loaded no errors or warning will be issued! -->
<!-- This default value plugs in the tld files of the reference implementation of JSF -->
<!--
<Set name="tldBundles"><Property name="org.eclipse.jetty.osgi.tldbundles" default="javax.faces.jsf-impl" /></Set>
</New>
</Arg>
</Call>
-->
</New>
</Arg>
</Call>

View File

@ -0,0 +1,78 @@
package org.eclipse.jetty.osgi.boot;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.AppProvider;
import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.osgi.framework.Bundle;
public class BundleContextProvider extends AbstractLifeCycle implements AppProvider
{
private DeploymentManager _deploymentManager;
private Map<String, App> _appMap = new HashMap<String, App>();
/* ------------------------------------------------------------ */
/**
* BundleApp
*
*
*/
public class BundleApp extends App
{
private String _contextFile;
private Bundle _bundle;
public BundleApp(DeploymentManager manager, AppProvider provider, String originId, Bundle bundle, String contextFile)
{
super(manager, provider, originId);
_bundle = bundle;
_contextFile = contextFile;
}
public String getContextFile ()
{
return _contextFile;
}
}
/* ------------------------------------------------------------ */
public void setDeploymentManager(DeploymentManager deploymentManager)
{
_deploymentManager = deploymentManager;
}
/* ------------------------------------------------------------ */
public ContextHandler createContextHandler(App app) throws Exception
{
//apply the contextFile, creating the ContextHandler, the DeploymentManager will register it in the ContextHandlerCollection
return null;
}
/* ------------------------------------------------------------ */
public void bundleAdded (Bundle bundle, String contextFiles)
{
if (contextFiles == null)
return;
//bundle defines OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH header,
//a comma separated list of context xml files that each define a ContextHandler (could be WebAppContexts)
String[] tmp = contextFiles.split(",;");
for (String contextFile : tmp)
{
String originId = bundle.getSymbolicName() + "-" + bundle.getVersion().toString() + "-"+contextFile;
BundleApp app = new BundleApp(_deploymentManager, this, originId, bundle, contextFile);
_appMap.put(originId,app);
_deploymentManager.addApp(app);
}
}
}

View File

@ -0,0 +1,763 @@
package org.eclipse.jetty.osgi.boot;
import java.io.File;
import java.net.URL;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
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.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.internal.webapp.OSGiWebappClassLoader;
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.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.packageadmin.PackageAdmin;
/**
* BundleWebAppProvider
*
*
*/
public class BundleWebAppProvider extends AbstractLifeCycle implements AppProvider
{
private static final Logger LOG = Log.getLogger(BundleWebAppProvider.class);
public static final String WATERMARK = "o.e.j.o.b.BWAP"; //indicates this class created the webapp
public static String __defaultConfigurations[] = {
"org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration",
"org.eclipse.jetty.webapp.WebXmlConfiguration",
"org.eclipse.jetty.osgi.boot.OSGiMetaInfConfiguration",
"org.eclipse.jetty.webapp.FragmentConfiguration",
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration"//,
//"org.eclipse.jetty.osgi.boot.jsp.TagLibOSGiConfiguration"
};
private DeploymentManager _deploymentManager;
private Map<String, App> _appMap = new HashMap<String, App>();
private Map<Bundle, App> _bundleMap = new HashMap<Bundle, App>();
private boolean _parentLoaderPriority;
private String _defaultsDescriptor;
private boolean _extractWars = true; //See WebAppContext.extractWars
private String _tldBundles;
private String[] _configurationClasses;
private ServerInstanceWrapper _serverWrapper;
private ServiceRegistration _serviceReg;
public static void setDefaultConfigurations (String[] defaultConfigs)
{
__defaultConfigurations = defaultConfigs;
}
public static String[] getDefaultConfigurations ()
{
return __defaultConfigurations;
}
/* ------------------------------------------------------------ */
/**
* BundleApp
*
*
*/
public class BundleApp extends App
{
private Bundle _bundle;
private String _contextPath;
private String _webAppPath;
private WebAppContext _webApp;
private Dictionary _properties;
public BundleApp(DeploymentManager manager, AppProvider provider, Bundle bundle, String originId)
{
super(manager, provider, originId);
_properties = bundle.getHeaders();
_bundle = bundle;
}
public BundleApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId)
{
super(manager, provider, originId);
_properties = properties;
_bundle = bundle;
}
public void setWebAppContext (WebAppContext webApp)
{
_webApp = webApp;
}
public Bundle getBundle()
{
return _bundle;
}
public String getContextPath()
{
return _contextPath;
}
public void setContextPath(String contextPath)
{
this._contextPath = contextPath;
}
public String getBundlePath()
{
return _webAppPath;
}
public void setWebAppPath(String path)
{
this._webAppPath = path;
}
public WebAppContext getWebAppContext()
throws Exception
{
if (_webApp != null)
{
configureWebApp();
return _webApp;
}
createWebApp();
return _webApp;
}
protected void createWebApp ()
throws Exception
{
_webApp = newWebApp();
configureWebApp();
}
protected WebAppContext newWebApp ()
{
WebAppContext webApp = new WebAppContext();
webApp.setAttribute(WATERMARK, WATERMARK);
return webApp;
}
public void configureWebApp()
throws Exception
{
_webApp.setContextPath(_contextPath);
String overrideBundleInstallLocation = (String)_properties.get(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE);
File bundleInstallLocation =
(overrideBundleInstallLocation == null
? BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(_bundle)
: new File(overrideBundleInstallLocation));
URL url = null;
//if the path wasn't set or it was ., then it is the root of the bundle's installed location
if (_webAppPath == null || _webAppPath.length() == 0 || ".".equals(_webAppPath))
{
url = bundleInstallLocation.toURI().toURL();
}
else
{
//Get the location of the root of the webapp inside the installed bundle
if (_webAppPath.startsWith("/") || _webAppPath.startsWith("file:"))
{
url = new File(_webAppPath).toURI().toURL();
}
else if (bundleInstallLocation != null && bundleInstallLocation.isDirectory())
{
url = new File(bundleInstallLocation, _webAppPath).toURI().toURL();
}
else if (bundleInstallLocation != null)
{
Enumeration<URL> urls = BundleFileLocatorHelperFactory.getFactory().getHelper().findEntries(_bundle, _webAppPath);
if (urls != null && urls.hasMoreElements())
url = urls.nextElement();
}
}
if (url == null)
{
throw new IllegalArgumentException("Unable to locate " + _webAppPath
+ " in "
+ (bundleInstallLocation != null ? bundleInstallLocation.getAbsolutePath() : "unlocated bundle '" + _bundle.getSymbolicName()+ "'"));
}
// converts bundleentry: protocol if necessary
_webApp.setWar(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(url).toString());
// Set up what has been configured on the provider
_webApp.setParentLoaderPriority(isParentLoaderPriority());
_webApp.setExtractWAR(isExtract());
if (getConfigurationClasses() != null)
_webApp.setConfigurationClasses(getConfigurationClasses());
else
_webApp.setConfigurationClasses(__defaultConfigurations);
for (int i=0;i<__defaultConfigurations.length;i++)
System.err.println(__defaultConfigurations[i]);
if (getDefaultsDescriptor() != null)
_webApp.setDefaultsDescriptor(getDefaultsDescriptor());
//Set up configuration from manifest headers
//extra classpath
String tmp = (String)_properties.get(OSGiWebappConstants.JETTY_EXTRA_CLASSPATH);
if (tmp != null)
_webApp.setExtraClasspath(tmp);
//web.xml
tmp = (String)_properties.get(OSGiWebappConstants.JETTY_WEB_XML_PATH);
if (tmp != null && tmp.trim().length() != 0)
{
File webXml = getFile (tmp, bundleInstallLocation);
if (webXml != null && webXml.exists())
_webApp.setDescriptor(webXml.getAbsolutePath());
}
//webdefault.xml
tmp = (String)_properties.get(OSGiWebappConstants.JETTY_DEFAULT_WEB_XML_PATH);
if (tmp != null)
{
File defaultWebXml = getFile (tmp, bundleInstallLocation);
if (defaultWebXml != null && defaultWebXml.exists())
_webApp.setDefaultsDescriptor(defaultWebXml.getAbsolutePath());
}
//Handle Require-TldBundle
//This is a comma separated list of names of bundles that contain tlds that this webapp uses.
//We add them to the webapp classloader.
String requireTldBundles = (String)_properties.get(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
String pathsToTldBundles = getPathsToRequiredBundles(requireTldBundles);
// make sure we provide access to all the jetty bundles by going
// through this bundle.
OSGiWebappClassLoader webAppLoader = new OSGiWebappClassLoader(_serverWrapper.getParentClassLoaderForWebapps(), _webApp, _bundle);
if (pathsToTldBundles != null)
webAppLoader.addClassPath(pathsToTldBundles);
_webApp.setClassLoader(webAppLoader);
// apply any META-INF/context.xml file that is found to configure
// the webapp first
applyMetaInfContextXml();
// pass the value of the require tld bundle so that the TagLibOSGiConfiguration
// can pick it up.
_webApp.setAttribute(OSGiWebappConstants.REQUIRE_TLD_BUNDLE, requireTldBundles);
//Set up some attributes
// rfc66
_webApp.setAttribute(OSGiWebappConstants.RFC66_OSGI_BUNDLE_CONTEXT, _bundle.getBundleContext());
// spring-dm-1.2.1 looks for the BundleContext as a different attribute.
// not a spec... but if we want to support
// org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext
// then we need to do this to:
_webApp.setAttribute("org.springframework.osgi.web." + BundleContext.class.getName(), _bundle.getBundleContext());
// also pass the bundle directly. sometimes a bundle does not have a
// bundlecontext.
// it is still useful to have access to the Bundle from the servlet
// context.
_webApp.setAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE, _bundle);
}
protected String getPathsToRequiredBundles (String requireTldBundles)
throws Exception
{
if (requireTldBundles == null) return null;
ServiceReference ref = _bundle.getBundleContext().getServiceReference(org.osgi.service.packageadmin.PackageAdmin.class.getName());
PackageAdmin packageAdmin = (ref == null) ? null : (PackageAdmin)_bundle.getBundleContext().getService(ref);
if (packageAdmin == null)
throw new IllegalStateException("Unable to get PackageAdmin reference to locate required Tld bundles");
StringBuilder paths = new StringBuilder();
String[] symbNames = requireTldBundles.split(", ");
for (String symbName : symbNames)
{
Bundle[] bs = packageAdmin.getBundles(symbName, null);
if (bs == null || bs.length == 0)
{
throw new IllegalArgumentException("Unable to locate the bundle '" + symbName
+ "' specified by "
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
+ " in manifest of "
+ (_bundle == null ? "unknown" : _bundle.getSymbolicName()));
}
File f = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bs[0]);
if (paths.length() > 0) paths.append(", ");
paths.append(f.toURI().toURL().toString());
LOG.debug("getPathsToRequiredBundles: bundle path=" + bs[0].getLocation() + " uri=" + f.toURI());
}
return paths.toString();
}
protected void applyMetaInfContextXml()
throws Exception
{
if (_bundle == null) return;
if (_webApp == null) return;
ClassLoader cl = Thread.currentThread().getContextClassLoader();
LOG.debug("Context classloader = " + cl);
try
{
Thread.currentThread().setContextClassLoader(_webApp.getClassLoader());
// find if there is a META-INF/context.xml file
URL contextXmlUrl = _bundle.getEntry("/META-INF/jetty-webapp-context.xml");
if (contextXmlUrl == null) return;
// Apply it just as the standard jetty ContextProvider would do
LOG.info("Applying " + contextXmlUrl + " to " + _webApp);
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXmlUrl);
HashMap properties = new HashMap();
properties.put("Server", getDeploymentManager().getServer());
xmlConfiguration.getProperties().putAll(properties);
xmlConfiguration.configure(_webApp);
}
finally
{
Thread.currentThread().setContextClassLoader(cl);
}
}
private File getFile (String file, File bundleInstall)
{
if (file == null)
return null;
if (file.startsWith("/") || file.startsWith("file:/"))
return new File(file);
else
return new File(bundleInstall, file);
}
}
public BundleWebAppProvider (ServerInstanceWrapper wrapper)
{
_serverWrapper = wrapper;
}
/* ------------------------------------------------------------ */
protected void doStart() throws Exception
{
//register as an osgi service, 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, _serverWrapper.getManagedServerName());
_serviceReg = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(this.getClass().getName(), this, properties);
super.doStart();
}
/* ------------------------------------------------------------ */
@Override
protected void doStop() throws Exception
{
//unregister ourselves
if (_serviceReg != null)
{
try
{
_serviceReg.unregister();
}
catch (Exception e)
{
LOG.warn(e);
}
}
super.doStop();
}
/* ------------------------------------------------------------ */
public DeploymentManager getDeploymentManager()
{
return _deploymentManager;
}
/* ------------------------------------------------------------ */
public void setDeploymentManager(DeploymentManager deploymentManager)
{
_deploymentManager = deploymentManager;
}
/* ------------------------------------------------------------ */
/**
* Get the parentLoaderPriority.
*
* @return the parentLoaderPriority
*/
public boolean isParentLoaderPriority()
{
return _parentLoaderPriority;
}
/* ------------------------------------------------------------ */
/**
* Set the parentLoaderPriority.
*
* @param parentLoaderPriority the parentLoaderPriority to set
*/
public void setParentLoaderPriority(boolean parentLoaderPriority)
{
_parentLoaderPriority = parentLoaderPriority;
}
/* ------------------------------------------------------------ */
/**
* Get the defaultsDescriptor.
*
* @return the defaultsDescriptor
*/
public String getDefaultsDescriptor()
{
return _defaultsDescriptor;
}
/* ------------------------------------------------------------ */
/**
* Set the defaultsDescriptor.
*
* @param defaultsDescriptor the defaultsDescriptor to set
*/
public void setDefaultsDescriptor(String defaultsDescriptor)
{
_defaultsDescriptor = defaultsDescriptor;
}
/* ------------------------------------------------------------ */
public boolean isExtract()
{
return _extractWars;
}
/* ------------------------------------------------------------ */
public void setExtract(boolean extract)
{
_extractWars = extract;
}
/* ------------------------------------------------------------ */
/**
* @param tldBundles Comma separated list of bundles that contain tld jars
* that should be setup on the jetty instances created here.
*/
public void setTldBundles(String tldBundles)
{
_tldBundles = tldBundles;
}
/* ------------------------------------------------------------ */
/**
* @return The list of bundles that contain tld jars that should be setup on
* the jetty instances created here.
*/
public String getTldBundles()
{
return _tldBundles;
}
/* ------------------------------------------------------------ */
/**
* @param configurations The configuration class names.
*/
public void setConfigurationClasses(String[] configurations)
{
_configurationClasses = configurations == null ? null : (String[]) configurations.clone();
}
/* ------------------------------------------------------------ */
/**
*
*/
public String[] getConfigurationClasses()
{
return _configurationClasses;
}
/* ------------------------------------------------------------ */
public void setServerInstanceWrapper(ServerInstanceWrapper wrapper)
{
_serverWrapper = wrapper;
}
/* ------------------------------------------------------------ */
public ContextHandler createContextHandler(App app) throws Exception
{
if (app == null)
return null;
if (!(app instanceof BundleApp))
throw new IllegalStateException(app+" is not a BundleApp");
//Create a WebAppContext suitable to deploy in OSGi
return ((BundleApp)app).getWebAppContext();
}
/* ------------------------------------------------------------ */
/**
* A bundle has been added that could be a webapp
* @param bundle
*/
public boolean bundleAdded (Bundle bundle)
{
if (bundle == null)
return false;
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(_serverWrapper.getParentClassLoaderForWebapps());
try
{
Dictionary headers = bundle.getHeaders();
//does the bundle have a OSGiWebappConstants.JETTY_WAR_FOLDER_PATH
if (headers.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH) != null)
{
String base = (String)headers.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH);
String contextPath = getContextPath(bundle);
String originId = getOriginId(bundle, base);
BundleApp app = new BundleApp(_deploymentManager, this, bundle, originId);
app.setWebAppPath(base);
app.setContextPath(contextPath);
_appMap.put(originId,app);
_bundleMap.put(bundle, app);
_deploymentManager.addApp(app);
return true;
}
//does the bundle have a WEB-INF/web.xml
if (bundle.getEntry("/WEB-INF/web.xml") != null)
{
String base = ".";
String contextPath = getContextPath(bundle);
String originId = getOriginId(bundle, base);
BundleApp app = new BundleApp(_deploymentManager, this, bundle, originId);
app.setContextPath(contextPath);
app.setWebAppPath(base);
_appMap.put(originId,app);
_bundleMap.put(bundle, app);
_deploymentManager.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 = ".";
String contextPath = (String)headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
String originId = getOriginId(bundle,base);
BundleApp app = new BundleApp(_deploymentManager, this, bundle, originId);
app.setContextPath(contextPath);
app.setWebAppPath(base);
_appMap.put(originId,app);
_bundleMap.put(bundle, app);
_deploymentManager.addApp(app);
return true;
}
return false;
}
finally
{
Thread.currentThread().setContextClassLoader(cl);
}
}
/* ------------------------------------------------------------ */
/**
* Bundle has been removed. If it was a webapp we deployed, undeploy it.
* @param bundle
*
* @return true if this was a webapp we had deployed, false otherwise
*/
public boolean bundleRemoved (Bundle bundle)
{
App app = _bundleMap.remove(bundle);
if (app != null)
{
_appMap.remove(app.getOriginId());
_deploymentManager.removeApp(app);
return true;
}
return false;
}
/* ------------------------------------------------------------ */
/**
* A webapp that was deployed as an osgi service has been added,
* and we want to deploy it.
*
* @param webApp
*/
public void serviceAdded (ServiceReference serviceRef, WebAppContext webApp)
{
Dictionary properties = new Hashtable<String,String>();
String contextPath = (String)serviceRef.getProperty(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
if (contextPath == null)
contextPath = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH);
String base = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH);
if (base == null)
base = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_WAR);
String webdefaultXml = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_DEFAULT_WEB_XML_PATH);
if (webdefaultXml == null)
webdefaultXml = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_DEFAULT_WEB_XML_PATH);
if (webdefaultXml != null)
properties.put(OSGiWebappConstants.JETTY_DEFAULT_WEB_XML_PATH, webdefaultXml);
String webXml = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_WEB_XML_PATH);
if (webXml == null)
webXml = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_WEB_XML_PATH);
if (webXml != null)
properties.put(OSGiWebappConstants.JETTY_WEB_XML_PATH, webXml);
String extraClassPath = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_EXTRA_CLASSPATH);
if (extraClassPath == null)
extraClassPath = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_EXTRA_CLASSPATH);
if (extraClassPath != null)
properties.put(OSGiWebappConstants.JETTY_EXTRA_CLASSPATH, extraClassPath);
String bundleInstallOverride = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE);
if (bundleInstallOverride == null)
bundleInstallOverride = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE);
if (bundleInstallOverride != null)
properties.put(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE, bundleInstallOverride);
String requiredTlds = (String)serviceRef.getProperty(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
if (requiredTlds == null)
requiredTlds = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE);
if (requiredTlds != null)
properties.put(OSGiWebappConstants.REQUIRE_TLD_BUNDLE, requiredTlds);
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(_serverWrapper.getParentClassLoaderForWebapps());
try
{
String originId = getOriginId(serviceRef.getBundle(), base);
BundleApp app = new BundleApp(_deploymentManager, this, serviceRef.getBundle(), properties, originId);
app.setContextPath(contextPath);
app.setWebAppPath(base);
app.setWebAppContext(webApp); //set the pre=made webapp instance
_appMap.put(originId,app);
_bundleMap.put(serviceRef.getBundle(), app);
_deploymentManager.addApp(app);
}
finally
{
Thread.currentThread().setContextClassLoader(cl);
}
}
/* ------------------------------------------------------------ */
/**
* @param webApp
*/
public boolean serviceRemoved (ServiceReference serviceRef, WebAppContext webApp)
{
App app = _bundleMap.remove(serviceRef.getBundle());
if (app != null)
{
_appMap.remove(app.getOriginId());
_deploymentManager.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;
}
/* ------------------------------------------------------------ */
private static String getOriginId(Bundle contributor, String path)
{
return contributor.getSymbolicName() + "-" + contributor.getVersion().toString() + (path.startsWith("/") ? path : "/" + path);
}
}

View File

@ -33,7 +33,7 @@ import org.osgi.framework.BundleException;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.BundleTracker;
//mavenBundle().groupId( "org.eclipse.jetty.osgi" ).artifactId( "jetty-osgi-boot-jsp" ).versionAsInProject().start(),
/**
* Bootstrap jetty and publish a default Server instance as an OSGi service.
*
@ -62,8 +62,6 @@ public class JettyBootstrapActivator implements BundleActivator
private ServiceRegistration _registeredServer;
private Server _server;
private JettyContextHandlerServiceTracker _jettyContextHandlerTracker;
private PackageAdminServiceTracker _packageAdminServiceTracker;
@ -159,10 +157,6 @@ public class JettyBootstrapActivator implements BundleActivator
}
finally
{
if (_server != null)
{
_server.stop();
}
INSTANCE = null;
}
}

View File

@ -0,0 +1,98 @@
package org.eclipse.jetty.osgi.boot;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
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.MetaInfConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.osgi.framework.Bundle;
public class OSGiMetaInfConfiguration extends MetaInfConfiguration
{
private static final Logger LOG = Log.getLogger(OSGiMetaInfConfiguration.class);
/**
* Inspect bundle fragments associated with the bundle of the webapp for web-fragment, resources, tlds.
*
* @see org.eclipse.jetty.webapp.MetaInfConfiguration#preConfigure(org.eclipse.jetty.webapp.WebAppContext)
*/
@Override
public void preConfigure(final WebAppContext context) throws Exception
{
List<Resource> frags = (List<Resource>) context.getAttribute(METAINF_FRAGMENTS);
List<Resource> resfrags = (List<Resource>) context.getAttribute(METAINF_RESOURCES);
List<Resource> tldfrags = (List<Resource>) context.getAttribute(METAINF_TLDS);
Bundle[] fragments = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles((Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE));
//TODO not convinced we need to do this, as we added any fragment jars to the MetaData.webInfJars in OSGiWebInfConfiguration,
//so surely the web-fragments and resources tlds etc can be discovered normally?
for (Bundle frag : fragments)
{
URL webFrag = frag.getEntry("/META-INF/web-fragment.xml");
Enumeration<URL> resEnum = frag.findEntries("/META-INF/resources", "*", true);
Enumeration<URL> tldEnum = frag.findEntries("/META-INF", "*.tld", false);
if (webFrag != null || (resEnum != null && resEnum.hasMoreElements()) || (tldEnum != null && tldEnum.hasMoreElements()))
{
try
{
if (webFrag != null)
{
if (frags == null)
{
frags = new ArrayList<Resource>();
context.setAttribute(METAINF_FRAGMENTS, frags);
}
frags.add(Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(frag).toURI()));
}
if (resEnum != null && resEnum.hasMoreElements())
{
URL resourcesEntry = frag.getEntry("/META-INF/resources/");
if (resourcesEntry == null)
{
// probably we found some fragments to a
// bundle.
// those are already contributed.
// so we skip this.
}
else
{
if (resfrags == null)
{
resfrags = new ArrayList<Resource>();
context.setAttribute(METAINF_RESOURCES, resfrags);
}
resfrags.add(Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(resourcesEntry)));
}
}
if (tldEnum != null && tldEnum.hasMoreElements())
{
if (tldfrags == null)
{
tldfrags = new ArrayList<Resource>();
context.setAttribute(METAINF_TLDS, tldfrags);
}
while (tldEnum.hasMoreElements())
{
URL tldUrl = tldEnum.nextElement();
tldfrags.add(Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(tldUrl)));
}
}
}
catch (Exception e)
{
LOG.warn("Unable to locate the bundle " + frag.getBundleId(), e);
}
}
}
super.preConfigure(context);
}
}

View File

@ -0,0 +1,255 @@
package org.eclipse.jetty.osgi.boot;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.regex.Pattern;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
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.util.resource.ResourceCollection;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
/**
* OSGiWebInfConfiguration
*
* Handle adding resources found in bundle fragments, and add them into the
*/
public class OSGiWebInfConfiguration extends WebInfConfiguration
{
private static final Logger LOG = Log.getLogger(WebInfConfiguration.class);
public static final String CONTAINER_BUNDLE_PATTERN = "org.eclipse.jetty.server.webapp.containerIncludeBundlePattern";
/**
* Check to see if there have been any bundle symbolic names added of bundles that should be
* regarded as being on the container classpath, and scanned for fragments, tlds etc etc.
* This can be defined in:
* <ol>
* <li>SystemProperty SYS_PROP_TLD_BUNDLES</li>
* <li>DeployerManager.setContextAttribute CONTAINER_BUNDLE_PATTERN</li>
* </ol>
*
* We also allow individual bundles to specify particular bundles that might include TLDs via the Require-Tlds
* MANIFEST.MF header. This is processed in the TagLibOSGiConfiguration class.
*
* @see org.eclipse.jetty.webapp.WebInfConfiguration#preConfigure(org.eclipse.jetty.webapp.WebAppContext)
*/
@Override
public void preConfigure(final WebAppContext context) throws Exception
{
super.preConfigure(context);
//Check to see if there have been any bundle symbolic names added of bundles that should be
//regarded as being on the container classpath, and scanned for fragments, tlds etc etc.
//This can be defined in:
// 1. SystemProperty SYS_PROP_TLD_BUNDLES
// 2. DeployerManager.setContextAttribute CONTAINER_BUNDLE_PATTERN
String tmp = (String)context.getAttribute(CONTAINER_BUNDLE_PATTERN);
Pattern pattern = (tmp==null?null:Pattern.compile(tmp));
List<String> names = new ArrayList<String>();
tmp = System.getProperty("org.eclipse.jetty.osgi.tldbundles");
if (tmp != null)
{
StringTokenizer tokenizer = new StringTokenizer(tmp, ", \n\r\t", false);
while (tokenizer.hasMoreTokens())
names.add(tokenizer.nextToken());
}
HashSet<Resource> matchingResources = new HashSet<Resource>();
if ( !names.isEmpty() || pattern != null)
{
Bundle[] bundles = FrameworkUtil.getBundle(OSGiWebInfConfiguration.class).getBundleContext().getBundles();
for (Bundle bundle : bundles)
{
if (pattern != null)
{
// if bundle symbolic name matches the pattern
if (pattern.matcher(bundle.getSymbolicName()).matches())
{
//get the file location of the jar and put it into the list of container jars that will be scanned for stuff (including tlds)
matchingResources.addAll(getBundleAsResource(bundle));
}
}
if (names != null)
{
//if there is an explicit bundle name, then check if it matches
if (names.contains(bundle.getSymbolicName()))
matchingResources.addAll(getBundleAsResource(bundle));
}
}
}
for (Resource r:matchingResources)
{
context.getMetaData().addContainerJar(r);
}
}
/**
* Consider the fragment bundles associated with the bundle of the webapp being deployed.
*
*
* @see org.eclipse.jetty.webapp.WebInfConfiguration#findJars(org.eclipse.jetty.webapp.WebAppContext)
*/
@Override
protected List<Resource> findJars (WebAppContext context)
throws Exception
{
List<Resource> mergedResources = new ArrayList<Resource>();
//get jars from WEB-INF/lib if there are any
List<Resource> webInfJars = super.findJars(context);
if (webInfJars != null)
mergedResources.addAll(webInfJars);
//add fragment jars as if in WEB-INF/lib of the associated webapp
Bundle[] fragments = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles((Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE));
for (Bundle frag : fragments)
{
File fragFile = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(frag);
mergedResources.add(Resource.newResource(fragFile.toURI()));
}
return mergedResources;
}
/**
* Allow fragments to supply some resources that are added to the baseResource of the webapp.
*
* The resources can be either prepended or appended to the baseResource.
*
* @see org.eclipse.jetty.webapp.WebInfConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext)
*/
@Override
public void configure(WebAppContext context) throws Exception
{
TreeMap<String, Resource> patchResourcesPath = new TreeMap<String, Resource>();
TreeMap<String, Resource> appendedResourcesPath = new TreeMap<String, Resource>();
Bundle bundle = (Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
if (bundle != null)
{
//TODO anything we need to do to improve PackageAdminServiceTracker?
Bundle[] fragments = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles(bundle);
if (fragments != null && fragments.length != 0)
{
// sorted extra resource base found in the fragments.
// the resources are either overriding the resourcebase found in the
// web-bundle
// or appended.
// amongst each resource we sort them according to the alphabetical
// order
// of the name of the internal folder and the symbolic name of the
// fragment.
// this is useful to make sure that the lookup path of those
// resource base defined by fragments is always the same.
// This natural order could be abused to define the order in which
// the base resources are
// looked up.
for (Bundle frag : fragments)
{
String fragFolder = (String) frag.getHeaders().get(OSGiWebappConstants.JETTY_WAR_FRAGMENT_FOLDER_PATH);
String patchFragFolder = (String) frag.getHeaders().get(OSGiWebappConstants.JETTY_WAR_PATCH_FRAGMENT_FOLDER_PATH);
if (fragFolder != null)
{
URL fragUrl = frag.getEntry(fragFolder);
if (fragUrl == null) { throw new IllegalArgumentException("Unable to locate " + fragFolder
+ " inside "
+ " the fragment '"
+ frag.getSymbolicName()
+ "'"); }
fragUrl = BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(fragUrl);
String key = fragFolder.startsWith("/") ? fragFolder.substring(1) : fragFolder;
appendedResourcesPath.put(key + ";" + frag.getSymbolicName(), Resource.newResource(fragUrl));
}
if (patchFragFolder != null)
{
URL patchFragUrl = frag.getEntry(patchFragFolder);
if (patchFragUrl == null)
{
throw new IllegalArgumentException("Unable to locate " + patchFragUrl
+ " inside fragment '"+frag.getSymbolicName()+ "'");
}
patchFragUrl = BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(patchFragUrl);
String key = patchFragFolder.startsWith("/") ? patchFragFolder.substring(1) : patchFragFolder;
patchResourcesPath.put(key + ";" + frag.getSymbolicName(), Resource.newResource(patchFragUrl));
}
}
if (!appendedResourcesPath.isEmpty())
context.setAttribute(WebInfConfiguration.RESOURCE_URLS, new ArrayList<Resource>(appendedResourcesPath.values()));
}
}
super.configure(context);
// place the patch resources at the beginning of the contexts's resource base
if (!patchResourcesPath.isEmpty())
{
Resource[] resources = new Resource[1+patchResourcesPath.size()];
ResourceCollection mergedResources = new ResourceCollection (patchResourcesPath.values().toArray(new Resource[patchResourcesPath.size()]));
System.arraycopy(patchResourcesPath.values().toArray(new Resource[patchResourcesPath.size()]), 0, resources, 0, patchResourcesPath.size());
resources[resources.length-1] = context.getBaseResource();
context.setBaseResource(new ResourceCollection(resources));
}
}
/**
* Resolves the bundle. Usually that would be a single URL per bundle. But we do some more work if there are jars
* embedded in the bundle.
*/
private List<Resource> getBundleAsResource(Bundle bundle)
throws Exception
{
List<Resource> resources = new ArrayList<Resource>();
File file = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bundle);
if (file.isDirectory())
{
for (File f : file.listFiles())
{
if (f.getName().endsWith(".jar") && f.isFile())
{
resources.add(Resource.newResource(f));
}
else if (f.isDirectory() && f.getName().equals("lib"))
{
for (File f2 : file.listFiles())
{
if (f2.getName().endsWith(".jar") && f2.isFile())
{
resources.add(Resource.newResource(f));
}
}
}
}
resources.add(Resource.newResource(file)); //TODO really???
}
else
{
resources.add(Resource.newResource(file));
}
return resources;
}
}

View File

@ -55,32 +55,60 @@ public class OSGiWebappConstants
* this will override static resources with the same name in the web-bundle. */
public static final String JETTY_WAR_PATCH_FRAGMENT_FOLDER_PATH = "Jetty-WarPatchFragmentFolderPath";
// OSGi ContextHandler service properties.
/** web app context path */
/**
* web app context path
* @deprecated see RFC66_WEB_CONTEXTPATH
*/
public static final String SERVICE_PROP_CONTEXT_PATH = "contextPath";
/** Path to the web application base folder */
/**
* Path to the web application base folder
* @deprecated see JETTY_WAR_FOLDER_PATH
*/
public static final String SERVICE_PROP_WAR = "war";
/** Extra classpath */
/**
* Extra classpath
* @deprecated see JETTY_EXTRA_CLASSPATH
*/
public static final String SERVICE_PROP_EXTRA_CLASSPATH = "extraClasspath";
/** jetty context file path */
public static final String JETTY_EXTRA_CLASSPATH = "Jetty-extraClasspath";
/**
* jetty context file path
* @deprecated see JETTY_CONTEXT_FILE_PATH
*/
public static final String SERVICE_PROP_CONTEXT_FILE_PATH = "contextFilePath";
/** web.xml file path */
/**
* web.xml file path
* @deprecated see JETTY_WEB_XML_PATH
*/
public static final String SERVICE_PROP_WEB_XML_PATH = "webXmlFilePath";
/** defaultweb.xml file path */
public static final String JETTY_WEB_XML_PATH = "Jetty-WebXmlFilePath";
/**
* defaultweb.xml file path
* @deprecated see JETTY_DEFAULT_WEB_XML_PATH
*/
public static final String SERVICE_PROP_DEFAULT_WEB_XML_PATH = "defaultWebXmlFilePath";
public static final String JETTY_DEFAULT_WEB_XML_PATH = "Jetty-defaultWebXmlFilePath";
/**
* path to the base folder that overrides the computed bundle installation
* location if not null useful to install webapps or jetty context files
* that are in fact not embedded in a bundle
* @deprecated see JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE
*/
public static final String SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE = "thisBundleInstall";
public static final String JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE = "Jetty-bundleInstall";
/**
* Comma separated list of bundles that contain tld file used by the webapp.
*/

View File

@ -177,8 +177,6 @@ public class DefaultJettyAtJettyHomeHelper
//register the Server instance as an OSGi service.
bundleContext.registerService(Server.class.getName(), server, properties);
// hookNestedConnectorToBridgeServlet(server);
}
/**
@ -226,6 +224,7 @@ public class DefaultJettyAtJettyHomeHelper
*/
private static String getJettyConfigurationURLs(Bundle configurationBundle)
{
System.err.println("GETTING JETTY PROPS FROM BUNDLE: "+configurationBundle.getSymbolicName());
String files = System.getProperty(SYS_PROP_JETTY_ETC_FILES, DEFAULT_JETTY_ETC_FILES);
StringTokenizer tokenizer = new StringTokenizer(files, ";,", false);

View File

@ -26,14 +26,14 @@ import java.util.StringTokenizer;
import org.eclipse.jetty.deploy.AppProvider;
import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.osgi.boot.BundleWebAppProvider;
import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
import org.eclipse.jetty.osgi.boot.OSGiAppProvider;
import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
import org.eclipse.jetty.osgi.boot.internal.jsp.TldLocatableURLClassloader;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.internal.webapp.LibExtClassLoaderHelper;
import org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleDeployerHelper;
import org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleTrackerCustomizer;
import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
import org.eclipse.jetty.osgi.boot.utils.internal.DefaultFileLocatorHelper;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.util.IO;
@ -78,9 +78,7 @@ public class ServerInstanceWrapper
private DeploymentManager _deploymentManager;
private OSGiAppProvider _provider;
private WebBundleDeployerHelper _webBundleDeployerHelper;
private BundleWebAppProvider _provider;
public ServerInstanceWrapper(String managedServerName)
{
@ -114,20 +112,11 @@ public class ServerInstanceWrapper
/**
* @return The app provider registered on this server.
*/
public OSGiAppProvider getOSGiAppProvider()
{
return _provider;
}
public Server getServer()
{
return _server;
}
public WebBundleDeployerHelper getWebBundleDeployerHelp()
{
return _webBundleDeployerHelper;
}
/**
* @return The collection of context handlers
@ -151,6 +140,8 @@ public class ServerInstanceWrapper
List<File> shared = sharedURLs != null ? extractFiles(sharedURLs) : null;
libExtClassLoader = LibExtClassLoaderHelper.createLibExtClassLoader(shared, null, server, JettyBootstrapActivator.class.getClassLoader());
System.err.println("LibExtClassLoader = "+libExtClassLoader);
Thread.currentThread().setContextClassLoader(libExtClassLoader);
configure(server, props);
@ -163,8 +154,10 @@ public class ServerInstanceWrapper
URL[] jarsWithTlds = getJarsWithTlds();
_commonParentClassLoaderForWebapps = jarsWithTlds == null ? libExtClassLoader : new TldLocatableURLClassloader(libExtClassLoader, jarsWithTlds);
System.err.println("common classloader = "+_commonParentClassLoaderForWebapps);
server.start();
_webBundleDeployerHelper = new WebBundleDeployerHelper(this);
//_webBundleDeployerHelper = new WebBundleDeployerHelper(this);
}
catch (Exception e)
{
@ -226,11 +219,19 @@ public class ServerInstanceWrapper
*/
private URL[] getJarsWithTlds() throws Exception
{
//Jars that are added onto the equivalent of the container classpath are:
// jstl jars: identified by the class WhenTag (and the boot-bundle manifest imports the jstl packages
// bundles identified by System property org.eclipse.jetty.osgi.tldbundles
// bundle symbolic name patterns defined in the DeploymentManager
//
// Any bundles mentioned in the Require-TldBundle manifest header of the webapp bundle MUST ALSO HAVE Import-Bundle
// in order to get them onto the classpath of the webapp.
ArrayList<URL> res = new ArrayList<URL>();
WebBundleDeployerHelper.staticInit();// that is not looking great.
for (WebappRegistrationCustomizer regCustomizer : WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS)
for (WebappRegistrationCustomizer regCustomizer : WebBundleTrackerCustomizer.JSP_REGISTRATION_HELPERS)
{
URL[] urls = regCustomizer.getJarsWithTlds(_provider, WebBundleDeployerHelper.BUNDLE_FILE_LOCATOR_HELPER);
URL[] urls = regCustomizer.getJarsWithTlds(_deploymentManager, BundleFileLocatorHelperFactory.getFactory().getHelper());
for (URL url : urls)
{
if (!res.contains(url)) res.add(url);
@ -324,9 +325,11 @@ public class ServerInstanceWrapper
for (AppProvider provider : _deploymentManager.getAppProviders())
{
if (provider instanceof OSGiAppProvider)
//if (provider instanceof OSGiAppProvider)
if (provider instanceof BundleWebAppProvider)
{
_provider = (OSGiAppProvider) provider;
//_provider = (OSGiAppProvider) provider;
_provider = (BundleWebAppProvider)provider;
break;
}
}
@ -335,10 +338,12 @@ public class ServerInstanceWrapper
// create it on the fly with reasonable default values.
try
{
_provider = new OSGiAppProvider();
_provider.setMonitoredDirResource(Resource.newResource(getDefaultOSGiContextsHome(new File(System.getProperty("jetty.home"))).toURI()));
//_provider = new OSGiAppProvider();
//_provider.setMonitoredDirResource(Resource.newResource(getDefaultOSGiContextsHome(new File(System.getProperty("jetty.home"))).toURI()));
_provider = new BundleWebAppProvider(this);
System.err.println("ADDED NEW BUNDLE WEBAPP PROVIDER");
}
catch (IOException e)
catch (Exception e)
{
LOG.warn(e);
}
@ -374,10 +379,6 @@ public class ServerInstanceWrapper
return new File(jettyHome, "/contexts");
}
File getOSGiContextsHome()
{
return _provider.getContextXmlDirAsFile();
}
/**
* @return the urls in this string.
@ -391,7 +392,7 @@ public class ServerInstanceWrapper
String tok = tokenizer.nextToken();
try
{
urls.add(((DefaultFileLocatorHelper) WebBundleDeployerHelper.BUNDLE_FILE_LOCATOR_HELPER).getLocalURL(new URL(tok)));
urls.add(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(new URL(tok)));
}
catch (Throwable mfe)
{
@ -415,7 +416,7 @@ public class ServerInstanceWrapper
try
{
URL url = new URL(tok);
url = ((DefaultFileLocatorHelper) WebBundleDeployerHelper.BUNDLE_FILE_LOCATOR_HELPER).getFileURL(url);
url = BundleFileLocatorHelperFactory.getFactory().getHelper().getFileURL(url);
if (url.getProtocol().equals("file"))
{
Resource res = Resource.newResource(url);

View File

@ -0,0 +1,41 @@
package org.eclipse.jetty.osgi.boot.internal.webapp;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* BundleFileLocatorHelperFactory
*
* Obtain a helper for locating files based on the bundle.
*/
public class BundleFileLocatorHelperFactory
{
private static final Logger LOG = Log.getLogger(BundleFileLocatorHelperFactory.class);
private static BundleFileLocatorHelperFactory _instance = new BundleFileLocatorHelperFactory();
private BundleFileLocatorHelperFactory() {}
public static BundleFileLocatorHelperFactory getFactory()
{
return _instance;
}
public BundleFileLocatorHelper getHelper()
{
BundleFileLocatorHelper helper = BundleFileLocatorHelper.DEFAULT;
try
{
//see if a fragment has supplied an alternative
helper = (BundleFileLocatorHelper) Class.forName(BundleFileLocatorHelper.CLASS_NAME).newInstance();
}
catch (Throwable t)
{
LOG.ignore(t);
}
return helper;
}
}

View File

@ -17,6 +17,7 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jetty.osgi.boot.BundleWebAppProvider;
import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
@ -34,6 +35,7 @@ import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
/**
* When a {@link ContextHandler} service is activated we look into it and if the
@ -54,7 +56,11 @@ import org.osgi.framework.ServiceReference;
*/
public class JettyContextHandlerServiceTracker implements ServiceListener
{
private static Logger __logger = Log.getLogger(WebBundleDeployerHelper.class.getName());
private static Logger __logger = Log.getLogger(JettyContextHandlerServiceTracker.class.getName());
public static final String FILTER = "(objectclass=" + BundleWebAppProvider.class.getName() + ")";
/** New style: ability to manage multiple jetty instances */
private final IManagedJettyServerRegistry _registry;
@ -71,12 +77,21 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
/** in charge of detecting changes in the osgi contexts home folder. */
private Scanner _scanner;
//track all instances of deployers of webapps as bundles
ServiceTracker _serviceTracker;
/**
* @param registry
*/
public JettyContextHandlerServiceTracker(IManagedJettyServerRegistry registry) throws Exception
{
_registry = registry;
//track all instances of deployers of webapps
Bundle myBundle = FrameworkUtil.getBundle(this.getClass());
_serviceTracker = new ServiceTracker(myBundle.getBundleContext(), FrameworkUtil.createFilter(FILTER),null);
_serviceTracker.open();
}
public void stop() throws Exception
@ -127,7 +142,29 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
reloadJettyContextHandler(filename, osgiContextHomeFolderCanonicalPath);
}
});
}
public BundleWebAppProvider getDeployer(String managedServerName)
{
if (managedServerName == null)
managedServerName = OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME;
ServiceReference sr = null;
ServiceReference[] references = _serviceTracker.getServiceReferences();
if (references != null)
{
for (ServiceReference ref:references)
{
String name = (String)ref.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
if (managedServerName.equalsIgnoreCase(name))
sr = ref;
}
}
if (sr != null)
return (BundleWebAppProvider)_serviceTracker.getService(sr);
return null;
}
/**
@ -135,6 +172,9 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
*
* @param ev The <code>ServiceEvent</code> object.
*/
/**
* @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
*/
public void serviceChanged(ServiceEvent ev)
{
ServiceReference sr = ev.getServiceReference();
@ -143,7 +183,9 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
case ServiceEvent.MODIFIED:
case ServiceEvent.UNREGISTERING:
{
ContextHandler ctxtHandler = unregisterInIndex(ev.getServiceReference());
//TODO unregister a ContextHandler, either with the BundleWebAppDeployer or with a BundleContextAppDeployer
/* ContextHandler ctxtHandler = unregisterInIndex(ev.getServiceReference());
if (ctxtHandler != null && !ctxtHandler.isStopped())
{
try
@ -154,7 +196,7 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
{
__logger.warn(e);
}
}
}*/
}
if (ev.getType() == ServiceEvent.UNREGISTERING)
{
@ -175,7 +217,23 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
// is configured elsewhere.
return;
}
String contextFilePath = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH);
//Get a jetty deployer targetted to the named server instance, or the default one if not named
if (contextHandler instanceof WebAppContext)
{
WebAppContext webApp = (WebAppContext)contextHandler;
String whichServer = (String)sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
BundleWebAppProvider deployer = getDeployer(whichServer);
deployer.serviceAdded(sr, webApp);
}
else
{
//TODO get a reference to a jetty deployer that is happy to deploy plain ContextHandlers
}
/* String contextFilePath = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH);
if (contextHandler instanceof WebAppContext && contextFilePath == null)
// it could be a web-application that will in fact be configured
// via a context file.
@ -274,7 +332,7 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
{
__logger.warn(e);
}
}
*/
}
break;
}
@ -375,10 +433,11 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
private IWebBundleDeployerHelper getWebBundleDeployerHelp(ServiceReference sr)
{
if (_registry == null) { return null; }
return null;
/* if (_registry == null) { return null; }
String managedServerName = (String) sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
ServerInstanceWrapper wrapper = getServerInstanceWrapper(managedServerName);
return wrapper != null ? wrapper.getWebBundleDeployerHelp() : null;
return wrapper != null ? wrapper.getWebBundleDeployerHelp() : null;*/
}
}

View File

@ -30,6 +30,7 @@ import java.util.jar.JarFile;
import javax.servlet.http.HttpServlet;
import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelper;
import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelperFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
@ -82,12 +83,12 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
* @param contributor The bundle that defines this web-application.
* @throws IOException
*/
public OSGiWebappClassLoader(ClassLoader parent, WebAppContext context, Bundle contributor, BundleClassLoaderHelper bundleClassLoaderHelper)
public OSGiWebappClassLoader(ClassLoader parent, WebAppContext context, Bundle contributor)
throws IOException
{
super(parent, context);
_contributor = contributor;
_osgiBundleClassLoader = bundleClassLoaderHelper.getBundleClassLoader(contributor);
_osgiBundleClassLoader = BundleClassLoaderHelperFactory.getFactory().getHelper().getBundleClassLoader(contributor);
}
/**

View File

@ -1,904 +0,0 @@
// ========================================================================
// Copyright (c) 2009 Intalio, Inc.
// ------------------------------------------------------------------------
// 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
// 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.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot.internal.webapp;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;
import org.eclipse.jetty.deploy.ContextDeployer;
import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelper;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
import org.eclipse.jetty.osgi.boot.utils.internal.DefaultBundleClassLoaderHelper;
import org.eclipse.jetty.osgi.boot.utils.internal.DefaultFileLocatorHelper;
import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.IO;
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.util.resource.ResourceCollection;
import org.eclipse.jetty.webapp.FragmentConfiguration;
import org.eclipse.jetty.webapp.TagLibConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleReference;
import org.osgi.service.packageadmin.PackageAdmin;
import org.osgi.util.tracker.ServiceTracker;
import org.xml.sax.SAXException;
/**
* Bridges the jetty deployers with the OSGi lifecycle where applications are
* managed inside OSGi-bundles.
* <p>
* This class should be called as a consequence of the activation of a new
* service that is a ContextHandler.<br/>
* This way the new webapps are exposed as OSGi services.
* </p>
* <p>
* Helper methods to register a bundle that is a web-application or a context.
* </p>
* Limitations:
* <ul>
* <li>support for jarred webapps is somewhat limited.</li>
* </ul>
*/
public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
{
private static Logger __logger = Log.getLogger(WebBundleDeployerHelper.class.getName());
private static boolean INITIALIZED = false;
/**
* By default set to: {@link DefaultBundleClassLoaderHelper}. It supports
* equinox and apache-felix fragment bundles that are specific to an OSGi
* implementation should set a different implementation.
*/
public static BundleClassLoaderHelper BUNDLE_CLASS_LOADER_HELPER = null;
/**
* By default set to: {@link DefaultBundleClassLoaderHelper}. It supports
* equinox and apache-felix fragment bundles that are specific to an OSGi
* implementation should set a different implementation.
*/
public static BundleFileLocatorHelper BUNDLE_FILE_LOCATOR_HELPER = null;
/**
* By default set to: {@link DefaultBundleClassLoaderHelper}. It supports
* equinox and apache-felix fragment bundles that are specific to an OSGi
* implementation should set a different implementation.
* <p>
* Several of those objects can be added here: For example we could have an
* optional fragment that setups a specific implementation of JSF for the
* whole of jetty-osgi.
* </p>
*/
public static Collection<WebappRegistrationCustomizer> JSP_REGISTRATION_HELPERS = new ArrayList<WebappRegistrationCustomizer>();
/**
* this class loader loads the jars inside {$jetty.home}/lib/ext it is meant
* as a migration path and for jars that are not OSGi ready. also gives
* access to the jsp jars.
*/
// private URLClassLoader _libExtClassLoader;
private ServerInstanceWrapper _wrapper;
public WebBundleDeployerHelper(ServerInstanceWrapper wrapper)
{
staticInit();
_wrapper = wrapper;
}
// Inject the customizing classes that might be defined in fragment bundles.
public static synchronized void staticInit()
{
if (!INITIALIZED)
{
INITIALIZED = true;
// setup the custom BundleClassLoaderHelper
try
{
BUNDLE_CLASS_LOADER_HELPER = (BundleClassLoaderHelper) Class.forName(BundleClassLoaderHelper.CLASS_NAME).newInstance();
}
catch (Throwable t)
{
// System.err.println("support for equinox and felix");
BUNDLE_CLASS_LOADER_HELPER = new DefaultBundleClassLoaderHelper();
}
// setup the custom FileLocatorHelper
try
{
BUNDLE_FILE_LOCATOR_HELPER = (BundleFileLocatorHelper) Class.forName(BundleFileLocatorHelper.CLASS_NAME).newInstance();
}
catch (Throwable t)
{
// System.err.println("no jsp/jasper support");
BUNDLE_FILE_LOCATOR_HELPER = new DefaultFileLocatorHelper();
}
}
}
/**
* Deploy a new web application on the jetty server.
*
* @param bundle The bundle
* @param webappFolderPath The path to the root of the webapp. Must be a
* path relative to bundle; either an absolute path.
* @param contextPath The context path. Must start with "/"
* @param extraClasspath
* @param overrideBundleInstallLocation
* @param requireTldBundle The list of bundles's symbolic names that contain
* tld files that are required by this WAB.
* @param webXmlPath
* @param defaultWebXmlPath TODO: parameter description
* @return The contexthandler created and started
* @throws Exception
*/
public WebAppContext registerWebapplication(Bundle bundle, String webappFolderPath, String contextPath, String extraClasspath,
String overrideBundleInstallLocation, String requireTldBundle, String webXmlPath, String defaultWebXmlPath,
WebAppContext webAppContext)
throws Exception
{
File bundleInstall = overrideBundleInstallLocation == null ? BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(bundle) : new File(overrideBundleInstallLocation);
File webapp = null;
URL baseWebappInstallURL = null;
if (webappFolderPath != null && webappFolderPath.length() != 0 && !webappFolderPath.equals("."))
{
if (webappFolderPath.startsWith("/") || webappFolderPath.startsWith("file:"))
{
webapp = new File(webappFolderPath);
}
else if (bundleInstall != null && bundleInstall.isDirectory())
{
webapp = new File(bundleInstall, webappFolderPath);
}
else if (bundleInstall != null)
{
Enumeration<URL> urls = BUNDLE_FILE_LOCATOR_HELPER.findEntries(bundle, webappFolderPath);
if (urls != null && urls.hasMoreElements())
{
baseWebappInstallURL = urls.nextElement();
}
}
}
else
{
webapp = bundleInstall;
}
if (baseWebappInstallURL == null && (webapp == null || !webapp.exists()))
{
throw new IllegalArgumentException("Unable to locate " + webappFolderPath
+ " inside "
+ (bundleInstall != null ? bundleInstall.getAbsolutePath() : "unlocated bundle '" + bundle.getSymbolicName()+ "'"));
}
if (baseWebappInstallURL == null && webapp != null)
{
baseWebappInstallURL = webapp.toURI().toURL();
}
return registerWebapplication(bundle, webappFolderPath, baseWebappInstallURL, contextPath, extraClasspath, bundleInstall, requireTldBundle, webXmlPath,
defaultWebXmlPath, webAppContext);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#
* registerWebapplication(org.osgi.framework.Bundle, java.lang.String,
* java.io.File, java.lang.String, java.lang.String, java.io.File,
* java.lang.String, java.lang.String)
*/
private WebAppContext registerWebapplication(Bundle contributor, String pathInBundleToWebApp, URL baseWebappInstallURL, String contextPath,
String extraClasspath, File bundleInstall, String requireTldBundle, String webXmlPath,
String defaultWebXmlPath, WebAppContext context)
throws Exception
{
ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
String[] oldServerClasses = null;
try
{
// apply any META-INF/context.xml file that is found to configure
// the webapp first
applyMetaInfContextXml(contributor, context);
// make sure we provide access to all the jetty bundles by going
// through this bundle.
OSGiWebappClassLoader composite = createWebappClassLoader(contributor);
// configure with access to all jetty classes and also all the
// classes
// that the contributor gives access to.
Thread.currentThread().setContextClassLoader(composite);
// converts bundleentry: protocol
baseWebappInstallURL = DefaultFileLocatorHelper.getLocalURL(baseWebappInstallURL);
context.setWar(baseWebappInstallURL.toString());
context.setContextPath(contextPath);
context.setExtraClasspath(extraClasspath);
if (webXmlPath != null && webXmlPath.length() != 0)
{
File webXml = null;
if (webXmlPath.startsWith("/") || webXmlPath.startsWith("file:/"))
{
webXml = new File(webXmlPath);
}
else
{
webXml = new File(bundleInstall, webXmlPath);
}
if (webXml.exists())
{
context.setDescriptor(webXml.getAbsolutePath());
}
}
if (defaultWebXmlPath == null || defaultWebXmlPath.length() == 0)
{
// use the one defined by the OSGiAppProvider.
defaultWebXmlPath = _wrapper.getOSGiAppProvider().getDefaultsDescriptor();
}
if (defaultWebXmlPath != null && defaultWebXmlPath.length() != 0)
{
File defaultWebXml = null;
if (defaultWebXmlPath.startsWith("/") || defaultWebXmlPath.startsWith("file:/"))
{
defaultWebXml = new File(defaultWebXmlPath);
}
else
{
defaultWebXml = new File(bundleInstall, defaultWebXmlPath);
}
if (defaultWebXml.exists())
{
context.setDefaultsDescriptor(defaultWebXml.getAbsolutePath());
}
}
// other parameters that might be defines on the OSGiAppProvider:
context.setParentLoaderPriority(_wrapper.getOSGiAppProvider().isParentLoaderPriority());
configureWebappClassLoader(contributor, context, composite, requireTldBundle);
configureWebAppContext(context, contributor, requireTldBundle);
// @see
// org.eclipse.jetty.webapp.JettyWebXmlConfiguration#configure(WebAppContext)
// during initialization of the webapp all the jetty packages are
// visible
// through the webapp classloader.
oldServerClasses = context.getServerClasses();
context.setServerClasses(null);
_wrapper.getOSGiAppProvider().addContext(contributor, pathInBundleToWebApp, context);
// support for patch resources. ideally this should be done inside a
// configurator.
List<Resource> patchResources = (List<Resource>) context.getAttribute(WebInfConfiguration.RESOURCE_URLS + ".patch");
if (patchResources != null)
{
LinkedList<Resource> resourcesPath = new LinkedList<Resource>();
// place the patch resources at the beginning of the lookup
// path.
resourcesPath.addAll(patchResources);
// then place the ones from the host web bundle.
Resource hostResources = context.getBaseResource();
if (hostResources instanceof ResourceCollection)
{
for (Resource re : ((ResourceCollection) hostResources).getResources())
{
resourcesPath.add(re);
}
}
else
{
resourcesPath.add(hostResources);
}
ResourceCollection rc = new ResourceCollection(resourcesPath.toArray(new Resource[resourcesPath.size()]));
context.setBaseResource(rc);
}
return context;
}
finally
{
if (context != null && oldServerClasses != null)
{
context.setServerClasses(oldServerClasses);
}
Thread.currentThread().setContextClassLoader(contextCl);
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#
* unregister(org.eclipse.jetty.server.handler.ContextHandler)
*/
public void unregister(ContextHandler contextHandler)
throws Exception
{
_wrapper.getOSGiAppProvider().removeContext(contextHandler);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#
* registerContext(org.osgi.framework.Bundle, java.lang.String,
* java.lang.String, java.lang.String)
*/
public ContextHandler registerContext(Bundle contributor, String contextFileRelativePath, String extraClasspath, String overrideBundleInstallLocation,
String requireTldBundle, ContextHandler handler)
throws Exception
{
File contextsHome = _wrapper.getOSGiAppProvider().getContextXmlDirAsFile();
if (contextsHome != null)
{
File prodContextFile = new File(contextsHome, contributor.getSymbolicName() + "/" + contextFileRelativePath);
if (prodContextFile.exists()) { return registerContext(contributor, contextFileRelativePath, prodContextFile, extraClasspath,
overrideBundleInstallLocation, requireTldBundle, handler); }
}
File rootFolder = overrideBundleInstallLocation != null ? Resource.newResource(overrideBundleInstallLocation).getFile() : BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(contributor);
File contextFile = rootFolder != null ? new File(rootFolder, contextFileRelativePath) : null;
if (contextFile != null && contextFile.exists())
{
return registerContext(contributor, contextFileRelativePath, contextFile, extraClasspath, overrideBundleInstallLocation, requireTldBundle, handler);
}
else
{
if (contextFileRelativePath.startsWith("./"))
{
contextFileRelativePath = contextFileRelativePath.substring(1);
}
if (!contextFileRelativePath.startsWith("/"))
{
contextFileRelativePath = "/" + contextFileRelativePath;
}
URL contextURL = contributor.getEntry(contextFileRelativePath);
if (contextURL != null)
{
Resource r = Resource.newResource(contextURL);
return registerContext(contributor, contextFileRelativePath, r.getInputStream(), extraClasspath, overrideBundleInstallLocation,
requireTldBundle, handler);
}
throw new IllegalArgumentException("Could not find the context " + "file "
+ contextFileRelativePath
+ " for the bundle "
+ contributor.getSymbolicName()
+ (overrideBundleInstallLocation != null ? " using the install location " + overrideBundleInstallLocation : ""));
}
}
/**
* This type of registration relies on jetty's complete context xml file.
* Context encompasses jndi and all other things. This makes the definition
* of the webapp a lot more self-contained.
*
* @param webapp
* @param contextPath
* @param classInBundle
* @throws Exception
*/
private ContextHandler registerContext(Bundle contributor, String pathInBundle, File contextFile, String extraClasspath,
String overrideBundleInstallLocation, String requireTldBundle, ContextHandler handler)
throws Exception
{
InputStream contextFileInputStream = null;
try
{
contextFileInputStream = new BufferedInputStream(new FileInputStream(contextFile));
return registerContext(contributor, pathInBundle, contextFileInputStream, extraClasspath, overrideBundleInstallLocation, requireTldBundle, handler);
}
finally
{
IO.close(contextFileInputStream);
}
}
/**
* @param contributor
* @param contextFileInputStream
* @return The ContextHandler created and registered or null if it did not
* happen.
* @throws Exception
*/
private ContextHandler registerContext(Bundle contributor, String pathInsideBundle, InputStream contextFileInputStream, String extraClasspath,
String overrideBundleInstallLocation, String requireTldBundle, ContextHandler handler)
throws Exception
{
ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
String[] oldServerClasses = null;
WebAppContext webAppContext = null;
try
{
// make sure we provide access to all the jetty bundles by going
// through this bundle.
OSGiWebappClassLoader composite = createWebappClassLoader(contributor);
// configure with access to all jetty classes and also all the
// classes
// that the contributor gives access to.
Thread.currentThread().setContextClassLoader(composite);
ContextHandler context = createContextHandler(handler, contributor, contextFileInputStream, extraClasspath, overrideBundleInstallLocation,
requireTldBundle);
if (context == null) { return null;// did not happen
}
// ok now register this webapp. we checked when we started jetty
// that there
// was at least one such handler for webapps.
// the actual registration must happen via the new Deployment API.
// _ctxtHandler.addHandler(context);
configureWebappClassLoader(contributor, context, composite, requireTldBundle);
if (context instanceof WebAppContext)
{
webAppContext = (WebAppContext) context;
// @see
// org.eclipse.jetty.webapp.JettyWebXmlConfiguration#configure(WebAppContext)
oldServerClasses = webAppContext.getServerClasses();
webAppContext.setServerClasses(null);
}
_wrapper.getOSGiAppProvider().addContext(contributor, pathInsideBundle, context);
return context;
}
finally
{
if (webAppContext != null)
{
webAppContext.setServerClasses(oldServerClasses);
}
Thread.currentThread().setContextClassLoader(contextCl);
}
}
/**
* Applies the properties of WebAppDeployer as defined in jetty.xml.
*
* @see {WebAppDeployer#scan} around the comment
* <code>// configure it</code>
*/
protected void configureWebAppContext(ContextHandler wah, Bundle contributor, String requireTldBundle)
throws IOException
{
// rfc66
wah.setAttribute(OSGiWebappConstants.RFC66_OSGI_BUNDLE_CONTEXT, contributor.getBundleContext());
// spring-dm-1.2.1 looks for the BundleContext as a different attribute.
// not a spec... but if we want to support
// org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext
// then we need to do this to:
wah.setAttribute("org.springframework.osgi.web." + BundleContext.class.getName(), contributor.getBundleContext());
// also pass the bundle directly. sometimes a bundle does not have a
// bundlecontext.
// it is still useful to have access to the Bundle from the servlet
// context.
wah.setAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE, contributor);
// pass the value of the require tld bundle so that the
// TagLibOSGiConfiguration
// can pick it up.
wah.setAttribute(OSGiWebappConstants.REQUIRE_TLD_BUNDLE, requireTldBundle);
Bundle[] fragments = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles(contributor);
if (fragments != null && fragments.length != 0)
{
// sorted extra resource base found in the fragments.
// the resources are either overriding the resourcebase found in the
// web-bundle
// or appended.
// amongst each resource we sort them according to the alphabetical
// order
// of the name of the internal folder and the symbolic name of the
// fragment.
// this is useful to make sure that the lookup path of those
// resource base defined by fragments is always the same.
// This natural order could be abused to define the order in which
// the base resources are
// looked up.
TreeMap<String, Resource> patchResourcesPath = new TreeMap<String, Resource>();
TreeMap<String, Resource> appendedResourcesPath = new TreeMap<String, Resource>();
for (Bundle frag : fragments)
{
String fragFolder = (String) frag.getHeaders().get(OSGiWebappConstants.JETTY_WAR_FRAGMENT_FOLDER_PATH);
String patchFragFolder = (String) frag.getHeaders().get(OSGiWebappConstants.JETTY_WAR_PATCH_FRAGMENT_FOLDER_PATH);
if (fragFolder != null)
{
URL fragUrl = frag.getEntry(fragFolder);
if (fragUrl == null) { throw new IllegalArgumentException("Unable to locate " + fragFolder
+ " inside "
+ " the fragment '"
+ frag.getSymbolicName()
+ "'"); }
fragUrl = DefaultFileLocatorHelper.getLocalURL(fragUrl);
String key = fragFolder.startsWith("/") ? fragFolder.substring(1) : fragFolder;
appendedResourcesPath.put(key + ";" + frag.getSymbolicName(), Resource.newResource(fragUrl));
}
if (patchFragFolder != null)
{
URL patchFragUrl = frag.getEntry(patchFragFolder);
if (patchFragUrl == null) { throw new IllegalArgumentException("Unable to locate " + patchFragUrl
+ " inside "
+ " the fragment '"
+ frag.getSymbolicName()
+ "'"); }
patchFragUrl = DefaultFileLocatorHelper.getLocalURL(patchFragUrl);
String key = patchFragFolder.startsWith("/") ? patchFragFolder.substring(1) : patchFragFolder;
patchResourcesPath.put(key + ";" + frag.getSymbolicName(), Resource.newResource(patchFragUrl));
}
}
if (!appendedResourcesPath.isEmpty())
{
wah.setAttribute(WebInfConfiguration.RESOURCE_URLS, new ArrayList<Resource>(appendedResourcesPath.values()));
}
if (!patchResourcesPath.isEmpty())
{
wah.setAttribute(WebInfConfiguration.RESOURCE_URLS + ".patch", new ArrayList<Resource>(patchResourcesPath.values()));
}
if (wah instanceof WebAppContext)
{
// This is the equivalent of what MetaInfConfiguration does. For
// OSGi bundles without the JarScanner
WebAppContext webappCtxt = (WebAppContext) wah;
// take care of the web-fragments, meta-inf resources and tld
// resources:
// similar to what MetaInfConfiguration does.
List<Resource> frags = (List<Resource>) wah.getAttribute(FragmentConfiguration.FRAGMENT_RESOURCES);
List<Resource> resfrags = (List<Resource>) wah.getAttribute(WebInfConfiguration.RESOURCE_URLS);
List<Resource> tldfrags = (List<Resource>) wah.getAttribute(TagLibConfiguration.TLD_RESOURCES);
for (Bundle frag : fragments)
{
URL webFrag = frag.getEntry("/META-INF/web-fragment.xml");
Enumeration<URL> resEnum = frag.findEntries("/META-INF/resources", "*", true);
Enumeration<URL> tldEnum = frag.findEntries("/META-INF", "*.tld", false);
if (webFrag != null || (resEnum != null && resEnum.hasMoreElements()) || (tldEnum != null && tldEnum.hasMoreElements()))
{
try
{
File fragFile = BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(frag);
// add it to the webinf jars collection:
// no need to check that it was not there yet: it
// was not there yet for sure.
Resource fragFileAsResource = Resource.newResource(fragFile.toURI());
webappCtxt.getMetaData().addWebInfJar(fragFileAsResource);
if (webFrag != null)
{
if (frags == null)
{
frags = new ArrayList<Resource>();
wah.setAttribute(FragmentConfiguration.FRAGMENT_RESOURCES, frags);
}
frags.add(fragFileAsResource);
}
if (resEnum != null && resEnum.hasMoreElements())
{
URL resourcesEntry = frag.getEntry("/META-INF/resources/");
if (resourcesEntry == null)
{
// probably we found some fragments to a
// bundle.
// those are already contributed.
// so we skip this.
}
else
{
if (resfrags == null)
{
resfrags = new ArrayList<Resource>();
wah.setAttribute(WebInfConfiguration.RESOURCE_URLS, resfrags);
}
resfrags.add(Resource.newResource(DefaultFileLocatorHelper.getLocalURL(resourcesEntry)));
}
}
if (tldEnum != null && tldEnum.hasMoreElements())
{
if (tldfrags == null)
{
tldfrags = new ArrayList<Resource>();
wah.setAttribute(TagLibConfiguration.TLD_RESOURCES, tldfrags);
}
while (tldEnum.hasMoreElements())
{
URL tldUrl = tldEnum.nextElement();
tldfrags.add(Resource.newResource(DefaultFileLocatorHelper.getLocalURL(tldUrl)));
}
}
}
catch (Exception e)
{
__logger.warn("Unable to locate the bundle " + frag.getBundleId(), e);
}
}
}
}
}
}
/**
* @See {@link ContextDeployer#scan}
* @param contextFile
* @return
*/
protected ContextHandler createContextHandler(ContextHandler handlerToConfigure, Bundle bundle, File contextFile, String extraClasspath,
String overrideBundleInstallLocation, String requireTldBundle)
{
try
{
return createContextHandler(handlerToConfigure, bundle, new BufferedInputStream(new FileInputStream(contextFile)), extraClasspath,
overrideBundleInstallLocation, requireTldBundle);
}
catch (FileNotFoundException e)
{
__logger.warn(e);
}
return null;
}
/**
* @See {@link ContextDeployer#scan}
* @param contextFile
* @return
*/
@SuppressWarnings("unchecked")
protected ContextHandler createContextHandler(ContextHandler handlerToConfigure, Bundle bundle, InputStream contextInputStream, String extraClasspath,
String overrideBundleInstallLocation, String requireTldBundle)
{
/*
* Do something identical to what the ContextProvider would have done:
* XmlConfiguration xmlConfiguration=new
* XmlConfiguration(resource.getURL()); HashMap properties = new
* HashMap(); properties.put("Server", _contexts.getServer()); if
* (_configMgr!=null) properties.putAll(_configMgr.getProperties());
*
* xmlConfiguration.setProperties(properties); ContextHandler
* context=(ContextHandler)xmlConfiguration.configure();
* context.setAttributes(new AttributesMap(_contextAttributes));
*/
try
{
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextInputStream);
HashMap properties = new HashMap();
properties.put("Server", _wrapper.getServer());
// insert the bundle's location as a property.
setThisBundleHomeProperty(bundle, properties, overrideBundleInstallLocation);
xmlConfiguration.getProperties().putAll(properties);
ContextHandler context = null;
if (handlerToConfigure == null)
{
context = (ContextHandler) xmlConfiguration.configure();
}
else
{
xmlConfiguration.configure(handlerToConfigure);
context = handlerToConfigure;
}
if (context instanceof WebAppContext)
{
((WebAppContext) context).setExtraClasspath(extraClasspath);
((WebAppContext) context).setParentLoaderPriority(_wrapper.getOSGiAppProvider().isParentLoaderPriority());
if (_wrapper.getOSGiAppProvider().getDefaultsDescriptor() != null && _wrapper.getOSGiAppProvider().getDefaultsDescriptor().length() != 0)
{
((WebAppContext) context).setDefaultsDescriptor(_wrapper.getOSGiAppProvider().getDefaultsDescriptor());
}
}
configureWebAppContext(context, bundle, requireTldBundle);
return context;
}
catch (FileNotFoundException e)
{
return null;
}
catch (SAXException e)
{
__logger.warn(e);
}
catch (IOException e)
{
__logger.warn(e);
}
catch (Throwable e)
{
__logger.warn(e);
}
finally
{
IO.close(contextInputStream);
}
return null;
}
/**
* Configure a classloader onto the context. If the context is a
* WebAppContext, build a WebAppClassLoader that has access to all the jetty
* classes thanks to the classloader of the JettyBootStrapper bundle and
* also has access to the classloader of the bundle that defines this
* context.
* <p>
* If the context is not a WebAppContext, same but with a simpler
* URLClassLoader. Note that the URLClassLoader is pretty much fake: it
* delegate all actual classloading to the parent classloaders.
* </p>
* <p>
* The URL[] returned by the URLClassLoader create contained specifically
* the jars that some j2ee tools expect and look into. For example the jars
* that contain tld files for jasper's jstl support.
* </p>
* <p>
* Also as the jars in the lib folder and the classes in the classes folder
* might already be in the OSGi classloader we filter them out of the
* WebAppClassLoader
* </p>
*
* @param context
* @param contributor
* @param webapp
* @param contextPath
* @param classInBundle
* @throws Exception
*/
protected void configureWebappClassLoader(Bundle contributor, ContextHandler context, OSGiWebappClassLoader webappClassLoader, String requireTldBundle)
throws Exception
{
if (context instanceof WebAppContext)
{
WebAppContext webappCtxt = (WebAppContext) context;
context.setClassLoader(webappClassLoader);
webappClassLoader.setWebappContext(webappCtxt);
String pathsToRequiredBundles = getPathsToRequiredBundles(context, contributor, requireTldBundle);
if (pathsToRequiredBundles != null) webappClassLoader.addClassPath(pathsToRequiredBundles);
}
else
{
context.setClassLoader(webappClassLoader);
}
}
/**
* No matter what the type of webapp, we create a WebappClassLoader.
*/
protected OSGiWebappClassLoader createWebappClassLoader(Bundle contributor)
throws Exception
{
// we use a temporary WebAppContext object.
// if this is a real webapp we will set it on it a bit later: once we
// know.
OSGiWebappClassLoader webappClassLoader = new OSGiWebappClassLoader(_wrapper.getParentClassLoaderForWebapps(), new WebAppContext(), contributor,
BUNDLE_CLASS_LOADER_HELPER);
return webappClassLoader;
}
protected void applyMetaInfContextXml(Bundle bundle, ContextHandler contextHandler)
throws Exception
{
if (bundle == null) return;
if (contextHandler == null) return;
ClassLoader cl = Thread.currentThread().getContextClassLoader();
__logger.info("Context classloader = " + cl);
try
{
Thread.currentThread().setContextClassLoader(_wrapper.getParentClassLoaderForWebapps());
// find if there is a META-INF/context.xml file
URL contextXmlUrl = bundle.getEntry("/META-INF/jetty-webapp-context.xml");
if (contextXmlUrl == null) return;
// Apply it just as the standard jetty ContextProvider would do
__logger.info("Applying " + contextXmlUrl + " to " + contextHandler);
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXmlUrl);
HashMap properties = new HashMap();
properties.put("Server", _wrapper.getServer());
xmlConfiguration.getProperties().putAll(properties);
xmlConfiguration.configure(contextHandler);
}
finally
{
Thread.currentThread().setContextClassLoader(cl);
}
}
/**
* Set the property &quot;this.bundle.install&quot; to point to the location
* of the bundle. Useful when <SystemProperty name="this.bundle.home"/> is
* used.
*/
private void setThisBundleHomeProperty(Bundle bundle, HashMap<String, Object> properties, String overrideBundleInstallLocation)
{
try
{
File location = overrideBundleInstallLocation != null ? new File(overrideBundleInstallLocation) : BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(bundle);
properties.put("this.bundle.install", location.getCanonicalPath());
properties.put("this.bundle.install.url", bundle.getEntry("/").toString());
}
catch (Throwable t)
{
__logger.warn("Unable to set 'this.bundle.install' " + " for the bundle " + bundle.getSymbolicName(), t);
}
}
private String getPathsToRequiredBundles(ContextHandler context, Bundle bundle, String requireTldBundle)
throws Exception
{
if (requireTldBundle == null) return null;
StringBuilder paths = new StringBuilder();
PackageAdmin packAdmin = getBundleAdmin();
DefaultFileLocatorHelper fileLocatorHelper = new DefaultFileLocatorHelper();
String[] symbNames = requireTldBundle.split(", ");
for (String symbName : symbNames)
{
Bundle[] bs = packAdmin.getBundles(symbName, null);
if (bs == null || bs.length == 0) { throw new IllegalArgumentException("Unable to locate the bundle '" + symbName
+ "' specified in the "
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
+ " of the manifest of "
+ (bundle == null ? "unknown" : bundle.getSymbolicName())); }
File f = fileLocatorHelper.getBundleInstallLocation(bs[0]);
if (paths.length() > 0) paths.append(", ");
__logger.debug("getPathsToRequiredBundles: bundle path=" + bs[0].getLocation() + " uri=" + f.toURI());
paths.append(f.toURI().toURL().toString());
}
return paths.toString();
}
private PackageAdmin getBundleAdmin()
{
Bundle bootBundle = ((BundleReference) OSGiWebappConstants.class.getClassLoader()).getBundle();
ServiceTracker serviceTracker = new ServiceTracker(bootBundle.getBundleContext(), PackageAdmin.class.getName(), null);
serviceTracker.open();
return (PackageAdmin) serviceTracker.getService();
}
}

View File

@ -13,16 +13,25 @@
package org.eclipse.jetty.osgi.boot.internal.webapp;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import org.eclipse.jetty.osgi.boot.BundleWebAppProvider;
import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
import org.eclipse.jetty.osgi.boot.internal.serverfactory.IManagedJettyServerRegistry;
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.FrameworkUtil;
import org.osgi.util.tracker.BundleTracker;
import org.osgi.util.tracker.BundleTrackerCustomizer;
import org.osgi.util.tracker.ServiceTracker;
/**
* Support bundles that declare the webapp directly through headers in their
@ -41,10 +50,6 @@ import org.osgi.util.tracker.BundleTrackerCustomizer;
* <li>Jetty-ContextFilePath</li>
* </ul>
* </p>
* And generate a jetty WebAppContext or another ContextHandler then registers
* it as service. Kind of simpler than declarative services and their xml files.
* Also avoid having the contributing bundle depend on jetty's package for
* WebApp.
*
* @author hmalphettes
*/
@ -52,6 +57,22 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer
{
private static final Logger LOG = Log.getLogger(WebBundleTrackerCustomizer.class);
public static Collection<WebappRegistrationCustomizer> JSP_REGISTRATION_HELPERS = new ArrayList<WebappRegistrationCustomizer>();
public static final String FILTER = "(&(objectclass=" + BundleWebAppProvider.class.getName() + ")"+
"("+OSGiServerConstants.MANAGED_JETTY_SERVER_NAME+"="+OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME+"))";
private ServiceTracker _serviceTracker;
public WebBundleTrackerCustomizer ()
throws Exception
{
Bundle myBundle = FrameworkUtil.getBundle(this.getClass());
//track all instances of deployers of webapps as bundles
_serviceTracker = new ServiceTracker(myBundle.getBundleContext(), FrameworkUtil.createFilter(FILTER),null);
_serviceTracker.open();
}
/**
* A bundle is being added to the <code>BundleTracker</code>.
*
@ -76,8 +97,7 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer
{
if (bundle.getState() == Bundle.ACTIVE)
{
boolean isWebBundle = register(bundle);
return isWebBundle ? bundle : null;
register(bundle);
}
else if (bundle.getState() == Bundle.STOPPING)
{
@ -142,123 +162,25 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer
*/
private boolean register(Bundle bundle)
{
Dictionary<?, ?> dic = bundle.getHeaders();
String warFolderRelativePath = (String) dic.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH);
if (warFolderRelativePath != null)
{
String contextPath = getWebContextPath(bundle, dic, false);
if (contextPath == null || !contextPath.startsWith("/"))
{
LOG.warn("The manifest header '" + OSGiWebappConstants.JETTY_WAR_FOLDER_PATH
+ ": "
+ warFolderRelativePath
+ "' in the bundle "
+ bundle.getSymbolicName()
+ " is not valid: there is no Web-ContextPath defined in the manifest.");
if (bundle == null)
return false;
}
// create the corresponding service and publish it in the context of
// the contributor bundle.
try
{
JettyBootstrapActivator.registerWebapplication(bundle, warFolderRelativePath, contextPath);
return true;
}
catch (Throwable e)
{
LOG.warn("Starting the web-bundle " + bundle.getSymbolicName() + " threw an exception.", e);
return true;// maybe it did not work maybe it did. safer to track this bundle.
}
}
else if (dic.get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH) != null)
{
String contextFileRelativePath = (String) dic.get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH);
if (contextFileRelativePath == null)
{
// nothing to register here.
//It might be a webapp bundle
//If it is, it will be deployed to our default jetty Server instance.
//Get a reference to a jetty BundleWebAppProvider as an osgi service that can do the deployment
BundleWebAppProvider deployer = (BundleWebAppProvider)_serviceTracker.getService();
if (deployer != null)
return deployer.bundleAdded(bundle);
return false;
}
// support for multiple webapps in the same bundle:
String[] pathes = contextFileRelativePath.split(",;");
for (String path : pathes)
{
try
{
JettyBootstrapActivator.registerContext(bundle, path.trim());
}
catch (Throwable e)
{
LOG.warn(e);
}
}
return true;
}
else
{
// support for OSGi-RFC66; disclaimer, no access to the actual
// (draft) of the spec: just a couple of posts on the
// world-wide-web.
URL rfc66Webxml = bundle.getEntry("/WEB-INF/web.xml");
if (rfc66Webxml == null && dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH) == null)
{
return false;// no webapp in here
}
// this is risky: should we make sure that there is no classes and
// jars directly available
// at the root of the of the bundle: otherwise they are accessible
// through the browser. we should enforce that the whole classpath
// is
// pointing to files and folders inside WEB-INF. We should
// filter-out
// META-INF too
String rfc66ContextPath = getWebContextPath(bundle, dic, rfc66Webxml == null);
try
{
JettyBootstrapActivator.registerWebapplication(bundle, ".", rfc66ContextPath);
return true;
}
catch (Throwable e)
{
LOG.warn(e);
return true;// maybe it did not work maybe it did. safer to track this bundle.
}
}
}
private String getWebContextPath(Bundle bundle, Dictionary<?, ?> dic, boolean webinfWebxmlExists)
{
String rfc66ContextPath = (String) dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
if (rfc66ContextPath == null)
{
if (!webinfWebxmlExists) { return 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("/");
rfc66ContextPath = toks[toks.length - 1];
// remove .jar, .war etc:
int lastDot = rfc66ContextPath.lastIndexOf('.');
if (lastDot != -1)
{
rfc66ContextPath = rfc66ContextPath.substring(0, lastDot);
}
}
if (!rfc66ContextPath.startsWith("/"))
{
rfc66ContextPath = "/" + rfc66ContextPath;
}
return rfc66ContextPath;
}
private void unregister(Bundle bundle)
{
// nothing to do: when the bundle is stopped, each one of its service
// reference is also stopped and that is what we use to stop the
// corresponding
// webapps registered in that bundle.
BundleWebAppProvider deployer = (BundleWebAppProvider)_serviceTracker.getService();
if (deployer != null)
deployer.bundleRemoved(bundle);
}
}

View File

@ -0,0 +1,44 @@
package org.eclipse.jetty.osgi.boot.utils;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* BundleClassLoaderHelperFactory
*
* Get a class loader helper adapted for the particular osgi environment.
*/
public class BundleClassLoaderHelperFactory
{
private static final Logger LOG = Log.getLogger(BundleClassLoaderHelperFactory.class);
private static BundleClassLoaderHelperFactory _instance = new BundleClassLoaderHelperFactory();
public static BundleClassLoaderHelperFactory getFactory()
{
return _instance;
}
private BundleClassLoaderHelperFactory()
{
}
public BundleClassLoaderHelper getHelper()
{
//use the default
BundleClassLoaderHelper helper = BundleClassLoaderHelper.DEFAULT;
try
{
//if a fragment has not provided their own impl
helper = (BundleClassLoaderHelper) Class.forName(BundleClassLoaderHelper.CLASS_NAME).newInstance();
}
catch (Throwable t)
{
LOG.ignore(t);
}
return helper;
}
}

View File

@ -84,4 +84,30 @@ public interface BundleFileLocatorHelper
*/
public Enumeration<URL> findEntries(Bundle bundle, String entryPath);
/**
* Only useful for equinox: on felix we get the file:// or jar:// url
* already. Other OSGi implementations have not been tested
* <p>
* Get a URL to the bundle entry that uses a common protocol (i.e. file:
* jar: or http: etc.).
* </p>
*
* @return a URL to the bundle entry that uses a common protocol
*/
public URL getLocalURL(URL url);
/**
* Only useful for equinox: on felix we get the file:// url already. Other
* OSGi implementations have not been tested
* <p>
* Get a URL to the content of the bundle entry that uses the file:
* protocol. The content of the bundle entry may be downloaded or extracted
* to the local file system in order to create a file: URL.
*
* @return a URL to the content of the bundle entry that uses the file:
* protocol
* </p>
*/
public URL getFileURL(URL url);
}

View File

@ -14,6 +14,7 @@ package org.eclipse.jetty.osgi.boot.utils;
import java.net.URL;
import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.osgi.boot.OSGiAppProvider;
/**
@ -49,6 +50,6 @@ public interface WebappRegistrationCustomizer
* @return array of URLs
* @throws Exception
*/
URL[] getJarsWithTlds(OSGiAppProvider provider, BundleFileLocatorHelper fileLocator) throws Exception;
URL[] getJarsWithTlds(DeploymentManager manager, BundleFileLocatorHelper fileLocator) throws Exception;
}

View File

@ -292,7 +292,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
*
* @return a URL to the bundle entry that uses a common protocol
*/
public static URL getLocalURL(URL url)
public URL getLocalURL(URL url)
{
if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol()))
{
@ -328,7 +328,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
* protocol
* </p>
*/
public static URL getFileURL(URL url)
public URL getFileURL(URL url)
{
if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol()))
{

View File

@ -25,6 +25,7 @@
<module>jetty-osgi-boot-warurl</module>
<module>jetty-osgi-httpservice</module>
<module>jetty-osgi-equinoxtools</module>
<module>test-jetty-osgi-webapp</module>
<module>test-jetty-osgi</module>
</modules>
<build>

View File

@ -0,0 +1,129 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty.osgi</groupId>
<artifactId>jetty-osgi-project</artifactId>
<version>7.6.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>test-jetty-osgi-webapp</artifactId>
<name>Jetty :: OSGi :: WebApp</name>
<description>Test Jetty OSGi Webapp bundle</description>
<properties>
<bundle-symbolic-name>${project.groupId}.webapp</bundle-symbolic-name>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.osgi</groupId>
<artifactId>org.eclipse.osgi</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.osgi</groupId>
<artifactId>org.eclipse.osgi.services</artifactId>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<!--
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>process-resources</phase>
<configuration>
<tasks>
<copy todir="target/classes/jettyhome">
<fileset dir="jettyhome">
<exclude name="**/*.log" />
</fileset>
</copy>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>artifact-jar</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
<execution>
<id>test-jar</id>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifestFile>target/classes/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-SymbolicName>org.eclipse.jetty.osgi.testapp;singleton:=true</Bundle-SymbolicName>
<Bundle-Name>Jetty OSGi Test WebApp</Bundle-Name>
<Bundle-Activator>com.acme.osgi.Activator</Bundle-Activator>
<Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment>
<!-- disable the uses directive: jetty will accomodate pretty much any versions
of the packages it uses; no need to reflect some tight dependency determined at
compilation time. -->
<_nouses>true</_nouses>
<Import-Package>
org.osgi.framework,
org.osgi.service.cm;version="1.2.0",
org.osgi.service.packageadmin,
org.osgi.service.startlevel;version="1.0.o",
org.osgi.service.url;version="1.0.0",
org.osgi.util.tracker;version="1.3.0",
org.slf4j;resolution:=optional,
org.slf4j.spi;resolution:=optional,
org.slf4j.helpers;resolution:=optional,
org.xml.sax,
org.xml.sax.helpers,
*
</Import-Package>
<DynamicImport-Package>org.eclipse.jetty.*;version="[7.6,8)"</DynamicImport-Package>
<!--Require-Bundle/-->
<!-- Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment -->
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,60 @@
// ========================================================================
// Copyright (c) 2012 Intalio, Inc.
// ------------------------------------------------------------------------
// 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 com.acme.osgi;
import java.util.Dictionary;
import java.util.Hashtable;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.webapp.WebAppContext;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.BundleTracker;
/**
* Bootstrap a webapp
*
*
*/
public class Activator implements BundleActivator
{
/**
*
* @param context
*/
public void start(BundleContext context) throws Exception
{
WebAppContext webapp = new WebAppContext();
Dictionary props = new Hashtable();
props.put("war",".");
props.put("contextPath","/acme");
//uiProps.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, serverName);
context.registerService(ContextHandler.class.getName(),webapp,props);
}
/**
* Stop the activator.
*
* @see
* org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception
{
}
}

View File

@ -0,0 +1,6 @@
<html>
<body>
<h1>Test OSGi WebApp</h1>
<p>Webapp registered by bundle as service successfully deployed.</p>
</body>
</html>

View File

@ -134,6 +134,15 @@
<scope>test</scope>
</dependency>
<!-- test osgi webapp service -->
<dependency>
<groupId>org.eclipse.jetty.osgi</groupId>
<artifactId>test-jetty-osgi-webapp</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam</artifactId>
@ -157,6 +166,12 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,43 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Configure the deployment manager -->
<!-- =========================================================== -->
<Call name="addBean">
<Arg>
<New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
<Set name="contexts">
<Ref id="Contexts" />
</Set>
<Call name="setContextAttribute">
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
<Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg>
</Call>
<!-- Providers of OSGi Apps -->
<!-- Call name="addAppProvider" -->
<!-- Arg -->
<!-- New class="org.eclipse.jetty.osgi.boot.OSGiAppProvider" -->
<!--
<Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set>
-->
<!--
<Set name="scanInterval">5</Set>
<Set name="contextXmlDir"><Property name="jetty.home" default="." />/contexts</Set>
-->
<!-- comma separated list of bundle symbolic names that contain custom tag libraries (*.tld files) -->
<!-- if those bundles don't exist or can't be loaded no errors or warning will be issued! -->
<!-- This default value plugs in the tld files of the reference implementation of JSF -->
<!--
<Set name="tldBundles"><Property name="org.eclipse.jetty.osgi.tldbundles" default="javax.faces.jsf-impl" /></Set>
</New>
</Arg>
</Call>
-->
</New>
</Arg>
</Call>
</Configure>

View File

@ -0,0 +1,26 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Add connector -->
<!-- =========================================================== -->
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
<Set name="host"><Property name="jetty.host" /></Set>
<Set name="port"><Property name="jetty.port" default="8080"/></Set>
<Set name="maxIdleTime">300000</Set>
<Set name="Acceptors">2</Set>
<Set name="statsOn">false</Set>
<Set name="confidentialPort">8443</Set>
<Set name="lowResourcesConnections">20000</Set>
<Set name="lowResourcesMaxIdleTime">5000</Set>
</New>
</Arg>
</Call>
</Configure>

View File

@ -0,0 +1,72 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<!-- =============================================================== -->
<!-- Configure the Jetty Server -->
<!-- -->
<!-- Documentation of this file format can be found at: -->
<!-- http://wiki.eclipse.org/Jetty/Reference/jetty.xml_syntax -->
<!-- =============================================================== -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Server Thread Pool -->
<!-- =========================================================== -->
<Set name="ThreadPool">
<!-- Default queued blocking threadpool -->
<New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<Set name="minThreads">10</Set>
<Set name="maxThreads">200</Set>
<Set name="detailedDump">false</Set>
</New>
</Set>
<!-- =========================================================== -->
<!-- Set handler Collection Structure -->
<!-- =========================================================== -->
<Set name="handler">
<New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
<Set name="handlers">
<Array type="org.eclipse.jetty.server.Handler">
<Item>
<New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
</Item>
<Item>
<New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
</Item>
<Item>
<New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/>
</Item>
</Array>
</Set>
</New>
</Set>
<!-- =========================================================== -->
<!-- extra options -->
<!-- =========================================================== -->
<Set name="stopAtShutdown">true</Set>
<Set name="sendServerVersion">true</Set>
<Set name="sendDateHeader">true</Set>
<Set name="gracefulShutdown">1000</Set>
<Set name="dumpAfterStart">false</Set>
<Set name="dumpBeforeStop">false</Set>
<!-- =========================================================== -->
<!-- jetty-jndi by default -->
<!-- =========================================================== -->
<Call class="java.lang.System" name="setProperty">
<Arg>java.naming.factory.initial</Arg>
<Arg><Property name="java.naming.factory.initial" default="org.eclipse.jetty.jndi.InitialContextFactory"/></Arg>
</Call>
<Call class="java.lang.System" name="setProperty">
<Arg>java.naming.factory.url.pkgs</Arg>
<Arg><Property name="java.naming.factory.url.pkgs" default="org.eclipse.jetty.jndi"/></Arg>
</Call>
</Configure>

View File

@ -121,7 +121,7 @@ public class TestJettyOSGiBootCore
* You will get a list of bundles installed by default
* plus your testcase, wrapped into a bundle called pax-exam-probe
*/
@Test
//@Test
public void testHttpService() throws Exception
{
// ServletContextHandler sch = null;

View File

@ -0,0 +1,166 @@
// ========================================================================
// Copyright (c) 2010 Intalio, Inc.
// ------------------------------------------------------------------------
// 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.
// Contributors:
// Hugues Malphettes - initial API and implementation
// ========================================================================
package org.eclipse.jetty.osgi.boot;
import static org.ops4j.pax.exam.CoreOptions.*;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import junit.framework.Assert;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpExchange;
import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Inject;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.container.def.PaxRunnerOptions;
import org.ops4j.pax.exam.junit.Configuration;
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
/**
* Pax-Exam to make sure the jetty-osgi-boot can be started along with the httpservice web-bundle.
* Then make sure we can deploy an OSGi service on the top of this.
*/
@RunWith( JUnit4TestRunner.class )
public class TestJettyOSGiBootWebAppAsService
{
private static final boolean LOGGING_ENABLED = false;
private static final boolean REMOTE_DEBUGGING = false;
@Inject
BundleContext bundleContext = null;
@Configuration
public static Option[] configure()
{
ArrayList<Option> options = new ArrayList<Option>();
options.addAll(TestJettyOSGiBootCore.provisionCoreJetty());
File base = MavenTestingUtils.getBasedir();
File src = new File (base, "src");
File tst = new File (src, "test");
File config = new File (tst, "config");
// Enable Logging
if(LOGGING_ENABLED) {
options.addAll(Arrays.asList(options(
// install log service using pax runners profile abstraction (there are more profiles, like DS)
// logProfile(),
// this is how you set the default log level when using pax logging (logProfile)
systemProperty( "org.ops4j.pax.logging.DefaultServiceLog.level" ).value( "INFO" )
)));
}
// Remote JDWP Debugging
if(REMOTE_DEBUGGING) {
options.addAll(Arrays.asList(options(
// this just adds all what you write here to java vm argumenents of the (new) osgi process.
PaxRunnerOptions.vmOption( "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5006" )
)));
}
// Standard Options
options.addAll(Arrays.asList(options(
PaxRunnerOptions.vmOption("-Djetty.port=9876 -Djetty.home="+config.getAbsolutePath()+" -D" + OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS +
"=etc/jetty.xml;etc/jetty-deployer.xml;etc/jetty-selector.xml;etc/jetty-testrealm.xml"),
/* orbit deps */
mavenBundle().groupId( "org.eclipse.jetty.orbit" ).artifactId( "javax.servlet.jsp" ).versionAsInProject(),
mavenBundle().groupId( "org.eclipse.jetty.orbit" ).artifactId( "javax.servlet.jsp.jstl" ).versionAsInProject(),
mavenBundle().groupId( "org.eclipse.jetty.orbit" ).artifactId( "javax.el" ).versionAsInProject(),
mavenBundle().groupId( "org.eclipse.jetty.orbit" ).artifactId( "com.sun.el" ).versionAsInProject(),
mavenBundle().groupId( "org.eclipse.jetty.orbit" ).artifactId( "org.apache.jasper.glassfish" ).versionAsInProject(),
mavenBundle().groupId( "org.eclipse.jetty.orbit" ).artifactId( "org.apache.taglibs.standard.glassfish" ).versionAsInProject(),
mavenBundle().groupId( "org.eclipse.jetty.orbit" ).artifactId( "org.eclipse.jdt.core" ).versionAsInProject(),
/* jetty-osgi deps */
mavenBundle().groupId( "org.eclipse.jetty.osgi" ).artifactId( "jetty-osgi-boot" ).versionAsInProject().start(),
mavenBundle().groupId( "org.eclipse.jetty.osgi" ).artifactId( "jetty-osgi-boot-jsp" ).versionAsInProject().start(),
//a bundle that registers a webapp as a service for the jetty osgi core to pick up and deploy
mavenBundle().groupId( "org.eclipse.jetty.osgi" ).artifactId( "test-jetty-osgi-webapp" ).versionAsInProject().start()
// mavenBundle().groupId( "org.eclipse.equinox.http" ).artifactId( "servlet" ).versionAsInProject().start()
)));
return options.toArray(new Option[options.size()]);
}
/**
* You will get a list of bundles installed by default
* plus your testcase, wrapped into a bundle called pax-exam-probe
*/
@Test
public void listBundles() throws Exception
{
Map<String,Bundle> bundlesIndexedBySymbolicName = new HashMap<String, Bundle>();
for( Bundle b : bundleContext.getBundles() )
{
bundlesIndexedBySymbolicName.put(b.getSymbolicName(), b);
System.err.println("Got " + b.getSymbolicName() + " " + b.getVersion().toString() + " " + b.getState());
}
Bundle osgiBoot = bundlesIndexedBySymbolicName.get("org.eclipse.jetty.osgi.boot");
Assert.assertNotNull("Could not find the org.eclipse.jetty.osgi.boot bundle", osgiBoot);
Assert.assertTrue(osgiBoot.getState() == Bundle.ACTIVE);
Bundle testWebBundle = bundlesIndexedBySymbolicName.get("org.eclipse.jetty.osgi.testapp");
Assert.assertNotNull("Could not find the org.eclipse.jetty.test-jetty-osgi-webapp.jar bundle", testWebBundle);
Assert.assertTrue("The bundle org.eclipse.jetty.testapp is not correctly resolved", testWebBundle.getState() == Bundle.ACTIVE);
//now test the jsp/dump.jsp
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
try
{
client.start();
ContentExchange getExchange = new ContentExchange();
getExchange.setURL("http://127.0.0.1:9876/acme/index.html");
getExchange.setMethod(HttpMethods.GET);
client.send(getExchange);
int state = getExchange.waitForDone();
Assert.assertEquals("state should be done", HttpExchange.STATUS_COMPLETED, state);
String content = null;
int responseStatus = getExchange.getResponseStatus();
Assert.assertEquals(HttpStatus.OK_200, responseStatus);
if (responseStatus == HttpStatus.OK_200) {
content = getExchange.getResponseContent();
}
Assert.assertTrue(content.indexOf("<h1>Test OSGi WebApp</h1>") != -1);
}
finally
{
client.stop();
}
}
}

View File

@ -29,6 +29,9 @@ import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpExchange;
import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -57,6 +60,12 @@ public class TestJettyOSGiBootWithJsp
public static Option[] configure()
{
File testrealm = new File("src/test/config/etc/jetty-testrealm.xml");
File base = MavenTestingUtils.getBasedir();
File src = new File (base, "src");
File tst = new File (src, "test");
File config = new File (tst, "config");
ArrayList<Option> options = new ArrayList<Option>();
options.addAll(TestJettyOSGiBootCore.provisionCoreJetty());
@ -81,8 +90,8 @@ public class TestJettyOSGiBootWithJsp
// Standard Options
options.addAll(Arrays.asList(options(
PaxRunnerOptions.vmOption("-Djetty.port=9876 -D" + OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS +
"=etc/jetty.xml;" + testrealm.getAbsolutePath()),
PaxRunnerOptions.vmOption("-Djetty.port=9876 -Djetty.home="+config.getAbsolutePath()+" -D" + OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS +
"=etc/jetty.xml;etc/jetty-deployer.xml;etc/jetty-selector.xml;etc/jetty-testrealm.xml"),
/* orbit deps */
mavenBundle().groupId( "org.eclipse.jetty.orbit" ).artifactId( "javax.servlet.jsp" ).versionAsInProject(),
@ -110,7 +119,7 @@ public class TestJettyOSGiBootWithJsp
* plus your testcase, wrapped into a bundle called pax-exam-probe
*/
@Test
@Ignore
public void listBundles() throws Exception
{
Map<String,Bundle> bundlesIndexedBySymbolicName = new HashMap<String, Bundle>();