Merge branch 'master' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project
This commit is contained in:
commit
dc7ae977ae
|
@ -0,0 +1,145 @@
|
|||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
Jetty Project
|
||||
Contributor License Agreement V1.0
|
||||
based on http://www.apache.org/licenses/
|
||||
|
||||
Thank you for your interest in the Jetty project by Mort Bay
|
||||
Consulting Pty. Ltd. Australia ("MortBay").
|
||||
In order to clarify the intellectual property license
|
||||
granted with Contributions from any person or entity, MortBay
|
||||
must have a Contributor License Agreement ("CLA") that has
|
||||
been signed by each Contributor, indicating agreement to the license
|
||||
terms below. This license is for your protection as a Contributor as
|
||||
well as the protection of MortBay and its users; it does not
|
||||
change your rights to use your own Contributions for any other
|
||||
purpose.
|
||||
|
||||
If you have not already done so, please complete this agreement
|
||||
and commit it to the Jetty repository at
|
||||
svn+ssh://svn.jetty.codehaus.org/home/projects/jetty/scm/jetty
|
||||
at legal/cla-USERNAME.txt using your authenticated codehaus ssh
|
||||
login. If you do not have commit privilege to the repository, please
|
||||
email the file to eclipse@eclipse.com. If possible, digitally sign
|
||||
the committed file, otherwise also send a signed Agreement to MortBay.
|
||||
|
||||
Please read this document carefully before signing and keep a copy for
|
||||
your records.
|
||||
|
||||
Full name: Thomas Becker
|
||||
E-Mail: thomas.becker00@googlemail.com
|
||||
Mailing Address:
|
||||
|
||||
You accept and agree to the following terms and conditions for Your
|
||||
present and future Contributions submitted to MortBay. In return,
|
||||
MortBay shall not use Your Contributions in a way that is contrary
|
||||
to the software license in effect at the time of the Contribution.
|
||||
Except for the license granted herein to MortBay and recipients of
|
||||
software distributed by MortBay, You reserve all right, title, and
|
||||
interest in and to Your Contributions.
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"You" (or "Your") shall mean the copyright owner or legal entity
|
||||
authorized by the copyright owner that is making this Agreement
|
||||
with MortBay. For legal entities, the entity making a
|
||||
Contribution and all other entities that control, are controlled
|
||||
by, or are under common control with that entity are considered to
|
||||
be a single Contributor. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"Contribution" shall mean any original work of authorship,
|
||||
including any modifications or additions to an existing work, that
|
||||
is intentionally submitted by You to MortBay for inclusion
|
||||
in, or documentation of, any of the products owned or managed by
|
||||
MortBay (the "Work"). For the purposes of this definition,
|
||||
"submitted" means any form of electronic, verbal, or written
|
||||
communication sent to MortBay or its representatives,
|
||||
including but not limited to communication on electronic mailing
|
||||
lists, source code control systems, and issue tracking systems that
|
||||
are managed by, or on behalf of, MortBay for the purpose of
|
||||
discussing and improving the Work, but excluding communication that
|
||||
is conspicuously marked or otherwise designated in writing by You
|
||||
as "Not a Contribution."
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this Agreement, You hereby grant to MortBay and to
|
||||
recipients of software distributed by MortBay a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare derivative works of,
|
||||
publicly display, publicly perform, sublicense, and distribute Your
|
||||
Contributions and such derivative works.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this Agreement, You hereby grant to MortBay and to
|
||||
recipients of software distributed by MortBay a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the
|
||||
Work, where such license applies only to those patent claims
|
||||
licensable by You that are necessarily infringed by Your
|
||||
Contribution(s) alone or by combination of Your Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If any
|
||||
entity institutes patent litigation against You or any other entity
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that your Contribution, or the Work to which you have contributed,
|
||||
constitutes direct or contributory patent infringement, then any
|
||||
patent licenses granted to that entity under this Agreement for
|
||||
that Contribution or Work shall terminate as of the date such
|
||||
litigation is filed.
|
||||
|
||||
4. You represent that you are legally entitled to grant the above
|
||||
license. If your employer(s) has rights to intellectual property
|
||||
that you create that includes your Contributions, you represent
|
||||
that you have received permission to make Contributions on behalf
|
||||
of that employer, that your employer has waived such rights for
|
||||
your Contributions to MortBay, or that your employer has
|
||||
executed a separate Corporate CLA with MortBay.
|
||||
|
||||
5. You represent that each of Your Contributions is Your original
|
||||
creation (see section 7 for submissions on behalf of others). You
|
||||
represent that Your Contribution submissions include complete
|
||||
details of any third-party license or other restriction (including,
|
||||
but not limited to, related patents and trademarks) of which you
|
||||
are personally aware and which are associated with any part of Your
|
||||
Contributions.
|
||||
|
||||
6. You are not expected to provide support for Your Contributions,
|
||||
except to the extent You desire to provide support. You may provide
|
||||
support for free, for a fee, or not at all. Unless required by
|
||||
applicable law or agreed to in writing, You provide Your
|
||||
Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties or conditions of TITLE, NON-
|
||||
INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
7. Should You wish to submit work that is not Your original creation,
|
||||
You may submit it to MortBay separately from any
|
||||
Contribution, identifying the complete details of its source and of
|
||||
any license or other restriction (including, but not limited to,
|
||||
related patents, trademarks, and license agreements) of which you
|
||||
are personally aware, and conspicuously marking the work as
|
||||
"Submitted on behalf of a third-party: [named here]".
|
||||
|
||||
8. You agree to notify MortBay of any facts or circumstances of
|
||||
which you become aware that would make these representations
|
||||
inaccurate in any respect.
|
||||
|
||||
Date: 2012-07-17
|
||||
Please sign:
|
||||
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.10 (GNU/Linux)
|
||||
|
||||
iQEcBAEBAgAGBQJQBb4tAAoJEMHhjBmtgF91HDcH/2nQDPuPztWFrBifnEoLF6Jl
|
||||
RUkfJzAPZaLDtDMfiDz7ucdRL1RDodmz4VIF2+fbKeBYQquZXfXIeEghz+tKriK3
|
||||
0M12guFkNLDteQp9h2p3Zu9JU3K0y4m84IDWq72HRmh1nRyD6lzZFhDGZ/D+69fF
|
||||
tgYG0FwEit00MAq/lRbsXHLpBOY+Jyh/Xy+QRnQTcAQ+tAgOlxds3w+JSs2sGdes
|
||||
YLAJQQacLeGh7EzD3F+CKuiwT4c5ub64LdXSlAVj1u2OjZBfqLaJ3FA60Ti+I3kn
|
||||
FNWKpzaeX+SQgMak6hsuatXi6EsVk6sIaskwEgl6+Xk+HYWy23ZQ8BKQRLKOZTw=
|
||||
=gAqN
|
||||
-----END PGP SIGNATURE-----
|
|
@ -1,6 +1,6 @@
|
|||
jetty-7.6.6-SNAPSHOT
|
||||
|
||||
jetty-7.6.5.v20120713 - 13 July 2012
|
||||
jetty-7.6.5.v20120716 - 16 July 2012
|
||||
+ 376717 Balancer Servlet with round robin support, contribution, added
|
||||
missing license
|
||||
+ 379250 Server is added to shutdown hook twice
|
||||
|
@ -19,6 +19,8 @@ jetty-7.6.5.v20120713 - 13 July 2012
|
|||
+ 383881 WebSocketHandler sets request as handled
|
||||
+ 384254 revert change to writable when not dispatched
|
||||
+ 384847 CrossOriginFilter is not working.
|
||||
+ 384896 JDBCSessionManager fails to load existing sessions on oracle when
|
||||
contextPath is /
|
||||
+ 384980 Jetty client unable to recover from Time outs when connection count
|
||||
per address hits max.
|
||||
+ JETTY-1525 Show handle status in response debug message
|
||||
|
|
|
@ -32,10 +32,11 @@ import org.eclipse.jetty.util.log.Log;
|
|||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.Ignore;
|
||||
|
||||
public class ExpirationWithLimitedConnectionsTest
|
||||
{
|
||||
@Test
|
||||
@Ignore
|
||||
public void testExpirationWithMaxConnectionPerAddressReached() throws Exception
|
||||
{
|
||||
final Logger logger = Log.getLogger("org.eclipse.jetty.client");
|
||||
|
|
|
@ -19,9 +19,12 @@ 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.osgi.boot.OSGiAppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
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 +59,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 +86,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 +98,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 +147,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())
|
||||
|
|
|
@ -25,10 +25,12 @@ 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 +48,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
|
||||
|
@ -81,12 +85,10 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
|
|||
{
|
||||
// sanity check:
|
||||
Class cl = getClass().getClassLoader().loadClass("org.apache.jasper.servlet.JspServlet");
|
||||
// System.err.println("found the jsp servlet: " + cl.getName());
|
||||
}
|
||||
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 +108,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 +130,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<?>>();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -9,6 +9,23 @@
|
|||
<Call name="addBean">
|
||||
<Arg>
|
||||
<New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
|
||||
<Set name="useStandardBindings">false</Set>
|
||||
<Set name="lifeCycleBindings">
|
||||
<Array type="org.eclipse.jetty.deploy.AppLifeCycle.Binding">
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.osgi.boot.OSGiDeployer"/>
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.deploy.bindings.StandardStarter"/>
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.deploy.bindings.StandardStopper"/>
|
||||
</Item>
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.osgi.boot.OSGiUndeployer"/>
|
||||
</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
<Set name="contexts">
|
||||
<Ref id="Contexts" />
|
||||
</Set>
|
||||
|
@ -17,22 +34,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>
|
||||
<!--
|
||||
<Set name="tldBundles"><Property name="org.eclipse.jetty.osgi.tldbundles" default="javax.faces.jsf-impl" /></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
-->
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -0,0 +1,355 @@
|
|||
// ========================================================================
|
||||
// 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 org.eclipse.jetty.osgi.boot;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
|
||||
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.utils.EventSender;
|
||||
import org.eclipse.jetty.osgi.boot.utils.OSGiClassLoader;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.JarResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* AbstractContextProvider
|
||||
*
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractContextProvider extends AbstractLifeCycle implements AppProvider
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractContextProvider.class);
|
||||
|
||||
private DeploymentManager _deploymentManager;
|
||||
|
||||
|
||||
private ServerInstanceWrapper _serverWrapper;
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* BundleApp
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class OSGiApp extends AbstractOSGiApp
|
||||
{
|
||||
private String _contextFile;
|
||||
private ContextHandler _contextHandler;
|
||||
private boolean _configured = false;
|
||||
|
||||
public OSGiApp(DeploymentManager manager, AppProvider provider, String originId, Bundle bundle, String contextFile)
|
||||
{
|
||||
super(manager, provider, bundle, originId);
|
||||
_contextFile = contextFile;
|
||||
}
|
||||
|
||||
public OSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String contextFile, String originId)
|
||||
{
|
||||
super(manager, provider, bundle, properties, originId);
|
||||
_contextFile = contextFile;
|
||||
}
|
||||
|
||||
public String getContextFile ()
|
||||
{
|
||||
return _contextFile;
|
||||
}
|
||||
|
||||
public void setHandler(ContextHandler h)
|
||||
{
|
||||
_contextHandler = h;
|
||||
}
|
||||
|
||||
public ContextHandler createContextHandler()
|
||||
throws Exception
|
||||
{
|
||||
configureContextHandler();
|
||||
return _contextHandler;
|
||||
}
|
||||
|
||||
public void configureContextHandler()
|
||||
throws Exception
|
||||
{
|
||||
if (_configured)
|
||||
return;
|
||||
|
||||
_configured = true;
|
||||
|
||||
//Override for bundle root may have been set
|
||||
String bundleOverrideLocation = (String)_properties.get(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE);
|
||||
if (bundleOverrideLocation == null)
|
||||
bundleOverrideLocation = (String)_properties.get(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE);
|
||||
|
||||
//Location on filesystem of bundle or the bundle override location
|
||||
File bundleLocation = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(_bundle);
|
||||
File root = (bundleOverrideLocation==null?bundleLocation:new File(bundleOverrideLocation));
|
||||
Resource rootResource = Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(root.toURI().toURL()));
|
||||
|
||||
//try and make sure the rootResource is useable - if its a jar then make it a jar file url
|
||||
if (rootResource.exists()&& !rootResource.isDirectory() && !rootResource.toString().startsWith("jar:"))
|
||||
{
|
||||
Resource jarResource = JarResource.newJarResource(rootResource);
|
||||
if (jarResource.exists() && jarResource.isDirectory())
|
||||
rootResource = jarResource;
|
||||
}
|
||||
|
||||
//Set the base resource of the ContextHandler, if not already set, can also be overridden by the context xml file
|
||||
if (_contextHandler != null && _contextHandler.getBaseResource() == null)
|
||||
{
|
||||
_contextHandler.setBaseResource(rootResource);
|
||||
}
|
||||
|
||||
//Use a classloader that knows about the common jetty parent loader, and also the bundle
|
||||
OSGiClassLoader classLoader = new OSGiClassLoader(getServerInstanceWrapper().getParentClassLoaderForWebapps(), _bundle);
|
||||
|
||||
//if there is a context file, find it and apply it
|
||||
if (_contextFile == null && _contextHandler == null)
|
||||
throw new IllegalStateException("No context file or ContextHandler");
|
||||
|
||||
if (_contextFile != null)
|
||||
{
|
||||
//apply the contextFile, creating the ContextHandler, the DeploymentManager will register it in the ContextHandlerCollection
|
||||
Resource res = null;
|
||||
|
||||
//try to find the context file in the filesystem
|
||||
if (_contextFile.startsWith("/"))
|
||||
res = getFileAsResource(_contextFile);
|
||||
|
||||
//try to find it relative to jetty home
|
||||
if (res == null)
|
||||
{
|
||||
//See if the specific server we are related to has jetty.home set
|
||||
String jettyHome = (String)getServerInstanceWrapper().getServer().getAttribute(OSGiServerConstants.JETTY_HOME);
|
||||
if (jettyHome != null)
|
||||
res = getFileAsResource(jettyHome, _contextFile);
|
||||
|
||||
//try to see if a SystemProperty for jetty.home is set
|
||||
if (res == null)
|
||||
{
|
||||
jettyHome = System.getProperty(OSGiServerConstants.JETTY_HOME);
|
||||
|
||||
if (jettyHome != null)
|
||||
{
|
||||
if (jettyHome.startsWith("\"") || jettyHome.startsWith("'"))
|
||||
jettyHome = jettyHome.substring(1);
|
||||
if (jettyHome.endsWith("\"") || (jettyHome.endsWith("'")))
|
||||
jettyHome = jettyHome.substring(0,jettyHome.length()-1);
|
||||
|
||||
res = getFileAsResource(jettyHome, _contextFile);
|
||||
if (LOG.isDebugEnabled()) LOG.debug("jetty home context file:"+res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//try to find it relative to an override location that has been specified
|
||||
if (res == null)
|
||||
{
|
||||
if (bundleOverrideLocation != null)
|
||||
{
|
||||
res = getFileAsResource(Resource.newResource(bundleOverrideLocation).getFile(), _contextFile);
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Bundle override location context file:"+res);
|
||||
}
|
||||
}
|
||||
|
||||
//try to find it relative to the bundle in which it is being deployed
|
||||
if (res == null)
|
||||
{
|
||||
if (_contextFile.startsWith("./"))
|
||||
_contextFile = _contextFile.substring(1);
|
||||
|
||||
if (!_contextFile.startsWith("/"))
|
||||
_contextFile = "/" + _contextFile;
|
||||
|
||||
URL contextURL = _bundle.getEntry(_contextFile);
|
||||
if (contextURL != null)
|
||||
res = Resource.newResource(contextURL);
|
||||
}
|
||||
|
||||
//apply the context xml file, either to an existing ContextHandler, or letting the
|
||||
//it create the ContextHandler as necessary
|
||||
if (res != null)
|
||||
{
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
|
||||
LOG.debug("Context classloader = " + cl);
|
||||
try
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(res.getInputStream());
|
||||
HashMap properties = new HashMap();
|
||||
//put the server instance in
|
||||
properties.put("Server", getServerInstanceWrapper().getServer());
|
||||
//put in the location of the bundle root
|
||||
properties.put("bundle.root", rootResource.toString());
|
||||
|
||||
// insert the bundle's location as a property.
|
||||
xmlConfiguration.getProperties().putAll(properties);
|
||||
|
||||
if (_contextHandler == null)
|
||||
_contextHandler = (ContextHandler) xmlConfiguration.configure();
|
||||
else
|
||||
xmlConfiguration.configure(_contextHandler);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Set up the class loader we created
|
||||
_contextHandler.setClassLoader(classLoader);
|
||||
|
||||
|
||||
//If a bundle/service property specifies context path, let it override the context xml
|
||||
String contextPath = (String)_properties.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
|
||||
if (contextPath == null)
|
||||
contextPath = (String)_properties.get(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH);
|
||||
if (contextPath != null)
|
||||
_contextHandler.setContextPath(contextPath);
|
||||
|
||||
//osgi Enterprise Spec r4 p.427
|
||||
_contextHandler.setAttribute(OSGiWebappConstants.OSGI_BUNDLECONTEXT, _bundle.getBundleContext());
|
||||
|
||||
//make sure we protect also the osgi dirs specified by OSGi Enterprise spec
|
||||
String[] targets = _contextHandler.getProtectedTargets();
|
||||
int length = (targets==null?0:targets.length);
|
||||
|
||||
String[] updatedTargets = null;
|
||||
if (targets != null)
|
||||
{
|
||||
updatedTargets = new String[length+OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length];
|
||||
System.arraycopy(targets, 0, updatedTargets, 0, length);
|
||||
|
||||
}
|
||||
else
|
||||
updatedTargets = new String[OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length];
|
||||
System.arraycopy(OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS, 0, updatedTargets, length, OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length);
|
||||
_contextHandler.setProtectedTargets(updatedTargets);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private Resource getFileAsResource (String dir, String file)
|
||||
{
|
||||
Resource r = null;
|
||||
try
|
||||
{
|
||||
File asFile = new File (dir, file);
|
||||
if (asFile.exists())
|
||||
r = Resource.newResource(asFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
r = null;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
private Resource getFileAsResource (String file)
|
||||
{
|
||||
Resource r = null;
|
||||
try
|
||||
{
|
||||
File asFile = new File (file);
|
||||
if (asFile.exists())
|
||||
r = Resource.newResource(asFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
r = null;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
private Resource getFileAsResource (File dir, String file)
|
||||
{
|
||||
Resource r = null;
|
||||
try
|
||||
{
|
||||
File asFile = new File (dir, file);
|
||||
if (asFile.exists())
|
||||
r = Resource.newResource(asFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
r = null;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public AbstractContextProvider(ServerInstanceWrapper wrapper)
|
||||
{
|
||||
_serverWrapper = wrapper;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ServerInstanceWrapper getServerInstanceWrapper()
|
||||
{
|
||||
return _serverWrapper;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.deploy.AppProvider#createContextHandler(org.eclipse.jetty.deploy.App)
|
||||
*/
|
||||
public ContextHandler createContextHandler(App app) throws Exception
|
||||
{
|
||||
if (app == null)
|
||||
return null;
|
||||
if (!(app instanceof OSGiApp))
|
||||
throw new IllegalStateException(app+" is not a BundleApp");
|
||||
|
||||
//Create a ContextHandler suitable to deploy in OSGi
|
||||
ContextHandler h = ((OSGiApp)app).createContextHandler();
|
||||
return h;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setDeploymentManager(DeploymentManager deploymentManager)
|
||||
{
|
||||
_deploymentManager = deploymentManager;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public DeploymentManager getDeploymentManager()
|
||||
{
|
||||
return _deploymentManager;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
// ========================================================================
|
||||
// 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 org.eclipse.jetty.osgi.boot;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.Hashtable;
|
||||
|
||||
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.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* AbstractBundleApp
|
||||
*
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractOSGiApp extends App
|
||||
{
|
||||
protected Bundle _bundle;
|
||||
protected Dictionary _properties;
|
||||
protected ServiceRegistration _registration;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, String originId)
|
||||
{
|
||||
super(manager, provider, originId);
|
||||
_properties = bundle.getHeaders();
|
||||
_bundle = bundle;
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId)
|
||||
{
|
||||
super(manager, provider, originId);
|
||||
_properties = properties;
|
||||
_bundle = bundle;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getBundleSymbolicName()
|
||||
{
|
||||
return _bundle.getSymbolicName();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getBundleVersionAsString()
|
||||
{
|
||||
if (_bundle.getVersion() == null)
|
||||
return null;
|
||||
return _bundle.getVersion().toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Bundle getBundle()
|
||||
{
|
||||
return _bundle;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setRegistration (ServiceRegistration registration)
|
||||
{
|
||||
_registration = registration;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ServiceRegistration getRegistration ()
|
||||
{
|
||||
return _registration;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void registerAsOSGiService() throws Exception
|
||||
{
|
||||
if (_registration == null)
|
||||
{
|
||||
Dictionary<String,String> properties = new Hashtable<String,String>();
|
||||
properties.put(OSGiWebappConstants.WATERMARK, OSGiWebappConstants.WATERMARK);
|
||||
if (getBundleSymbolicName() != null)
|
||||
properties.put(OSGiWebappConstants.OSGI_WEB_SYMBOLICNAME, getBundleSymbolicName());
|
||||
if (getBundleVersionAsString() != null)
|
||||
properties.put(OSGiWebappConstants.OSGI_WEB_VERSION, getBundleVersionAsString());
|
||||
properties.put(OSGiWebappConstants.OSGI_WEB_CONTEXTPATH, getContextPath());
|
||||
ServiceRegistration rego = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(ContextHandler.class.getName(), getContextHandler(), properties);
|
||||
setRegistration(rego);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void deregisterAsOSGiService() throws Exception
|
||||
{
|
||||
if (_registration == null)
|
||||
return;
|
||||
|
||||
_registration.unregister();
|
||||
_registration = null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,548 @@
|
|||
// ========================================================================
|
||||
// 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 org.eclipse.jetty.osgi.boot;
|
||||
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
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.osgi.boot.utils.EventSender;
|
||||
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;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* AbstractWebAppProvider
|
||||
*
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractWebAppProvider extends AbstractLifeCycle implements AppProvider
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractWebAppProvider.class);
|
||||
|
||||
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"
|
||||
};
|
||||
|
||||
public static void setDefaultConfigurations (String[] defaultConfigs)
|
||||
{
|
||||
__defaultConfigurations = defaultConfigs;
|
||||
}
|
||||
|
||||
public static String[] getDefaultConfigurations ()
|
||||
{
|
||||
return __defaultConfigurations;
|
||||
}
|
||||
|
||||
|
||||
private boolean _parentLoaderPriority;
|
||||
|
||||
private String _defaultsDescriptor;
|
||||
|
||||
private boolean _extractWars = true; //See WebAppContext.extractWars
|
||||
|
||||
private String _tldBundles;
|
||||
|
||||
private DeploymentManager _deploymentManager;
|
||||
|
||||
private String[] _configurationClasses;
|
||||
|
||||
private ServerInstanceWrapper _serverWrapper;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* OSGiApp
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class OSGiApp extends AbstractOSGiApp
|
||||
{
|
||||
private String _contextPath;
|
||||
private String _webAppPath;
|
||||
private WebAppContext _webApp;
|
||||
|
||||
public OSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, String originId)
|
||||
{
|
||||
super(manager, provider, bundle, originId);
|
||||
}
|
||||
|
||||
public OSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId)
|
||||
{
|
||||
super(manager, provider, bundle, properties, originId);
|
||||
}
|
||||
|
||||
public void setWebAppContext (WebAppContext webApp)
|
||||
{
|
||||
_webApp = webApp;
|
||||
}
|
||||
|
||||
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 ContextHandler createContextHandler()
|
||||
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(OSGiWebappConstants.WATERMARK, OSGiWebappConstants.WATERMARK);
|
||||
|
||||
//make sure we protect also the osgi dirs specified by OSGi Enterprise spec
|
||||
String[] targets = webApp.getProtectedTargets();
|
||||
String[] updatedTargets = null;
|
||||
if (targets != null)
|
||||
{
|
||||
updatedTargets = new String[targets.length+OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length];
|
||||
System.arraycopy(targets, 0, updatedTargets, 0, targets.length);
|
||||
}
|
||||
else
|
||||
updatedTargets = new String[OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length];
|
||||
System.arraycopy(OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS, 0, updatedTargets, targets.length, OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length);
|
||||
webApp.setProtectedTargets(updatedTargets);
|
||||
|
||||
return webApp;
|
||||
}
|
||||
|
||||
|
||||
public void configureWebApp()
|
||||
throws Exception
|
||||
{
|
||||
//TODO turn this around and let any context.xml file get applied first, and have the properties override
|
||||
_webApp.setContextPath(_contextPath);
|
||||
|
||||
//osgi Enterprise Spec r4 p.427
|
||||
_webApp.setAttribute(OSGiWebappConstants.OSGI_BUNDLECONTEXT, _bundle.getBundleContext());
|
||||
|
||||
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);
|
||||
|
||||
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());
|
||||
|
||||
//TODO replace this with getting the InputStream so we don't cache in URL
|
||||
// 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 AbstractWebAppProvider (ServerInstanceWrapper wrapper)
|
||||
{
|
||||
_serverWrapper = wrapper;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* 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 ServerInstanceWrapper getServerInstanceWrapper()
|
||||
{
|
||||
return _serverWrapper;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public DeploymentManager getDeploymentManager()
|
||||
{
|
||||
return _deploymentManager;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.deploy.AppProvider#setDeploymentManager(org.eclipse.jetty.deploy.DeploymentManager)
|
||||
*/
|
||||
public void setDeploymentManager(DeploymentManager deploymentManager)
|
||||
{
|
||||
_deploymentManager = deploymentManager;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ContextHandler createContextHandler(App app) throws Exception
|
||||
{
|
||||
if (app == null)
|
||||
return null;
|
||||
if (!(app instanceof OSGiApp))
|
||||
throw new IllegalStateException(app+" is not a BundleApp");
|
||||
|
||||
//Create a WebAppContext suitable to deploy in OSGi
|
||||
ContextHandler ch = ((OSGiApp)app).createContextHandler();
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static String getOriginId(Bundle contributor, String path)
|
||||
{
|
||||
return contributor.getSymbolicName() + "-" + contributor.getVersion().toString() + (path.startsWith("/") ? path : "/" + path);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
// ========================================================================
|
||||
// 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 org.eclipse.jetty.osgi.boot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.osgi.boot.utils.EventSender;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* BundleContextProvider
|
||||
*
|
||||
* Handles deploying bundles that define a context xml file for configuring them.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class BundleContextProvider extends AbstractContextProvider implements BundleProvider
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractContextProvider.class);
|
||||
|
||||
|
||||
private Map<String, App> _appMap = new HashMap<String, App>();
|
||||
|
||||
private Map<Bundle, List<App>> _bundleMap = new HashMap<Bundle, List<App>>();
|
||||
|
||||
private ServiceRegistration _serviceRegForBundles;
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public BundleContextProvider(ServerInstanceWrapper wrapper)
|
||||
{
|
||||
super(wrapper);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
//register as an osgi service for deploying contexts defined in a bundle, advertising the name of the jetty Server instance we are related to
|
||||
Dictionary<String,String> properties = new Hashtable<String,String>();
|
||||
properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, getServerInstanceWrapper().getManagedServerName());
|
||||
_serviceRegForBundles = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(BundleProvider.class.getName(), this, properties);
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
//unregister ourselves
|
||||
if (_serviceRegForBundles != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_serviceRegForBundles.unregister();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param bundle
|
||||
* @param contextFiles
|
||||
* @return
|
||||
*/
|
||||
public boolean bundleAdded (Bundle bundle) throws Exception
|
||||
{
|
||||
if (bundle == null)
|
||||
return false;
|
||||
|
||||
String contextFiles = (String)bundle.getHeaders().get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH);
|
||||
if (contextFiles == null)
|
||||
contextFiles = (String)bundle.getHeaders().get(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH);
|
||||
|
||||
if (contextFiles == null)
|
||||
return false;
|
||||
|
||||
boolean added = false;
|
||||
//bundle defines JETTY_CONTEXT_FILE_PATH header,
|
||||
//a comma separated list of context xml files that each define a ContextHandler
|
||||
//TODO: (could be WebAppContexts)
|
||||
String[] tmp = contextFiles.split(",;");
|
||||
for (String contextFile : tmp)
|
||||
{
|
||||
String originId = bundle.getSymbolicName() + "-" + bundle.getVersion().toString() + "-"+contextFile;
|
||||
OSGiApp app = new OSGiApp(getDeploymentManager(), this, originId, bundle, contextFile);
|
||||
_appMap.put(originId,app);
|
||||
List<App> apps = _bundleMap.get(bundle);
|
||||
if (apps == null)
|
||||
{
|
||||
apps = new ArrayList<App>();
|
||||
_bundleMap.put(bundle, apps);
|
||||
}
|
||||
apps.add(app);
|
||||
getDeploymentManager().addApp(app);
|
||||
}
|
||||
|
||||
return added; //true if even 1 context from this bundle was added
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Bundle has been removed. If it was a context we deployed, undeploy it.
|
||||
* @param bundle
|
||||
*
|
||||
* @return true if this was a context we had deployed, false otherwise
|
||||
*/
|
||||
public boolean bundleRemoved (Bundle bundle) throws Exception
|
||||
{
|
||||
List<App> apps = _bundleMap.remove(bundle);
|
||||
boolean removed = false;
|
||||
if (apps != null)
|
||||
{
|
||||
for (App app:apps)
|
||||
{
|
||||
_appMap.remove(app.getOriginId());
|
||||
getDeploymentManager().removeApp(app);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
return removed; //true if even 1 context was removed associated with this bundle
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
// ========================================================================
|
||||
// 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 org.eclipse.jetty.osgi.boot;
|
||||
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
public interface BundleProvider
|
||||
{
|
||||
public boolean bundleAdded (Bundle bundle) throws Exception;
|
||||
|
||||
public boolean bundleRemoved (Bundle bundle) throws Exception;
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
// ========================================================================
|
||||
// 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 org.eclipse.jetty.osgi.boot;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.osgi.boot.utils.EventSender;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* BundleWebAppProvider
|
||||
*
|
||||
* A Jetty Provider that knows how to deploy a WebApp contained inside a Bundle.
|
||||
*
|
||||
*/
|
||||
public class BundleWebAppProvider extends AbstractWebAppProvider implements BundleProvider
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractWebAppProvider.class);
|
||||
|
||||
/**
|
||||
* Map of Bundle to App. Used when a Bundle contains a webapp.
|
||||
*/
|
||||
private Map<Bundle, App> _bundleMap = new HashMap<Bundle, App>();
|
||||
|
||||
private ServiceRegistration _serviceRegForBundles;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param wrapper
|
||||
*/
|
||||
public BundleWebAppProvider (ServerInstanceWrapper wrapper)
|
||||
{
|
||||
super(wrapper);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
|
||||
*/
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
//register as an osgi service for deploying bundles, advertising the name of the jetty Server instance we are related to
|
||||
Dictionary<String,String> properties = new Hashtable<String,String>();
|
||||
properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, getServerInstanceWrapper().getManagedServerName());
|
||||
_serviceRegForBundles = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(BundleProvider.class.getName(), this, properties);
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
|
||||
*/
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
//unregister ourselves
|
||||
if (_serviceRegForBundles != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_serviceRegForBundles.unregister();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* A bundle has been added that could be a webapp
|
||||
* @param bundle
|
||||
*/
|
||||
public boolean bundleAdded (Bundle bundle) throws Exception
|
||||
{
|
||||
if (bundle == null)
|
||||
return false;
|
||||
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(getServerInstanceWrapper().getParentClassLoaderForWebapps());
|
||||
String contextPath = null;
|
||||
try
|
||||
{
|
||||
Dictionary headers = bundle.getHeaders();
|
||||
|
||||
//does the bundle have a OSGiWebappConstants.JETTY_WAR_FOLDER_PATH
|
||||
if (headers.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH) != null)
|
||||
{
|
||||
String base = (String)headers.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH);
|
||||
contextPath = getContextPath(bundle);
|
||||
String originId = getOriginId(bundle, base);
|
||||
|
||||
//TODO : we don't know whether an app is actually deployed, as deploymentManager swallows all
|
||||
//exceptions inside the impl of addApp. Need to send the Event and also register as a service
|
||||
//only if the deployment succeeded
|
||||
OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId);
|
||||
app.setWebAppPath(base);
|
||||
app.setContextPath(contextPath);
|
||||
_bundleMap.put(bundle, app);
|
||||
getDeploymentManager().addApp(app);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//does the bundle have a WEB-INF/web.xml
|
||||
if (bundle.getEntry("/WEB-INF/web.xml") != null)
|
||||
{
|
||||
String base = ".";
|
||||
contextPath = getContextPath(bundle);
|
||||
String originId = getOriginId(bundle, base);
|
||||
|
||||
OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId);
|
||||
app.setContextPath(contextPath);
|
||||
app.setWebAppPath(base);
|
||||
_bundleMap.put(bundle, app);
|
||||
getDeploymentManager().addApp(app);
|
||||
return true;
|
||||
}
|
||||
|
||||
//does the bundle define a OSGiWebappConstants.RFC66_WEB_CONTEXTPATH
|
||||
if (headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH) != null)
|
||||
{
|
||||
//Could be a static webapp with no web.xml
|
||||
String base = ".";
|
||||
contextPath = (String)headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
|
||||
String originId = getOriginId(bundle,base);
|
||||
|
||||
OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId);
|
||||
app.setContextPath(contextPath);
|
||||
app.setWebAppPath(base);
|
||||
_bundleMap.put(bundle, app);
|
||||
getDeploymentManager().addApp(app);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Bundle has been removed. If it was a webapp we deployed, undeploy it.
|
||||
* @param bundle
|
||||
*
|
||||
* @return true if this was a webapp we had deployed, false otherwise
|
||||
*/
|
||||
public boolean bundleRemoved (Bundle bundle) throws Exception
|
||||
{
|
||||
App app = _bundleMap.remove(bundle);
|
||||
if (app != null)
|
||||
{
|
||||
getDeploymentManager().removeApp(app);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private static String getContextPath(Bundle bundle)
|
||||
{
|
||||
Dictionary<?, ?> headers = bundle.getHeaders();
|
||||
String contextPath = (String) headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
|
||||
if (contextPath == null)
|
||||
{
|
||||
// extract from the last token of the bundle's location:
|
||||
// (really ?could consider processing the symbolic name as an alternative
|
||||
// the location will often reflect the version.
|
||||
// maybe this is relevant when the file is a war)
|
||||
String location = bundle.getLocation();
|
||||
String toks[] = location.replace('\\', '/').split("/");
|
||||
contextPath = toks[toks.length - 1];
|
||||
// remove .jar, .war etc:
|
||||
int lastDot = contextPath.lastIndexOf('.');
|
||||
if (lastDot != -1)
|
||||
contextPath = contextPath.substring(0, lastDot);
|
||||
}
|
||||
if (!contextPath.startsWith("/"))
|
||||
contextPath = "/" + contextPath;
|
||||
|
||||
return contextPath;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -62,8 +62,6 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
|
||||
private ServiceRegistration _registeredServer;
|
||||
|
||||
private Server _server;
|
||||
|
||||
private JettyContextHandlerServiceTracker _jettyContextHandlerTracker;
|
||||
|
||||
private PackageAdminServiceTracker _packageAdminServiceTracker;
|
||||
|
@ -91,12 +89,12 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
// should activate.
|
||||
_packageAdminServiceTracker = new PackageAdminServiceTracker(context);
|
||||
|
||||
// track Server instances that we should support as deployment targets
|
||||
// track jetty Server instances that we should support as deployment targets
|
||||
_jettyServerServiceTracker = new JettyServerServiceTracker();
|
||||
context.addServiceListener(_jettyServerServiceTracker, "(objectclass=" + Server.class.getName() + ")");
|
||||
|
||||
// track ContextHandler class instances and deploy them to one of the known Servers
|
||||
_jettyContextHandlerTracker = new JettyContextHandlerServiceTracker(_jettyServerServiceTracker);
|
||||
_jettyContextHandlerTracker = new JettyContextHandlerServiceTracker();
|
||||
context.addServiceListener(_jettyContextHandlerTracker, "(objectclass=" + ContextHandler.class.getName() + ")");
|
||||
|
||||
// Create a default jetty instance right now.
|
||||
|
@ -125,7 +123,6 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
}
|
||||
if (_jettyContextHandlerTracker != null)
|
||||
{
|
||||
_jettyContextHandlerTracker.stop();
|
||||
context.removeServiceListener(_jettyContextHandlerTracker);
|
||||
_jettyContextHandlerTracker = null;
|
||||
}
|
||||
|
@ -159,10 +156,6 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
}
|
||||
finally
|
||||
{
|
||||
if (_server != null)
|
||||
{
|
||||
_server.stop();
|
||||
}
|
||||
INSTANCE = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,728 +0,0 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2009-2010 Mortbay, 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:
|
||||
// Greg Wilkins - initial API and implementation
|
||||
// ========================================================================
|
||||
package org.eclipse.jetty.osgi.boot;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.deploy.providers.ContextProvider;
|
||||
import org.eclipse.jetty.deploy.providers.ScanningAppProvider;
|
||||
import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
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.WebAppContext;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.BundleException;
|
||||
import org.osgi.framework.Constants;
|
||||
|
||||
/**
|
||||
* AppProvider for OSGi. Supports the configuration of ContextHandlers and
|
||||
* WebApps. Extends the AbstractAppProvider to support the scanning of context
|
||||
* files located outside of the bundles.
|
||||
* <p>
|
||||
* This provider must not be called outside of jetty.boot: it should always be
|
||||
* called via the OSGi service listener.
|
||||
* </p>
|
||||
* <p>
|
||||
* This provider supports the same set of parameters than the WebAppProvider as
|
||||
* it supports the deployment of WebAppContexts. Except for the scanning of the
|
||||
* webapps directory.
|
||||
* </p>
|
||||
* <p>
|
||||
* When the parameter autoInstallOSGiBundles is set to true, OSGi bundles that
|
||||
* are located in the monitored directory are installed and started after the
|
||||
* framework as finished auto-starting all the other bundles. Warning: only use
|
||||
* this for development.
|
||||
* </p>
|
||||
*/
|
||||
public class OSGiAppProvider extends ScanningAppProvider implements AppProvider
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(OSGiAppProvider.class);
|
||||
|
||||
private boolean _extractWars = true;
|
||||
|
||||
private boolean _parentLoaderPriority = false;
|
||||
|
||||
private String _defaultsDescriptor;
|
||||
|
||||
private String _tldBundles;
|
||||
|
||||
private String[] _configurationClasses;
|
||||
|
||||
private boolean _autoInstallOSGiBundles = true;
|
||||
|
||||
// Keep track of the bundles that were installed and that are waiting for
|
||||
// the
|
||||
// framework to complete its initialization.
|
||||
Set<Bundle> _pendingBundlesToStart = null;
|
||||
|
||||
/**
|
||||
* When a context file corresponds to a deployed bundle and is changed we
|
||||
* reload the corresponding bundle.
|
||||
*/
|
||||
private static class Filter implements FilenameFilter
|
||||
{
|
||||
OSGiAppProvider _enclosedInstance;
|
||||
|
||||
public boolean accept(File dir, String name)
|
||||
{
|
||||
File file = new File(dir, name);
|
||||
if (fileMightBeAnOSGiBundle(file)) { return true; }
|
||||
if (!file.isDirectory())
|
||||
{
|
||||
String contextName = getDeployedAppName(name);
|
||||
if (contextName != null)
|
||||
{
|
||||
App app = _enclosedInstance.getDeployedApps().get(contextName);
|
||||
return app != null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contextFileName for example myContext.xml
|
||||
* @return The context, for example: myContext; null if this was not a
|
||||
* suitable contextFileName.
|
||||
*/
|
||||
private static String getDeployedAppName(String contextFileName)
|
||||
{
|
||||
String lowername = contextFileName.toLowerCase();
|
||||
if (lowername.endsWith(".xml"))
|
||||
{
|
||||
String contextName = contextFileName.substring(0, lowername.length() - ".xml".length());
|
||||
return contextName;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading the display name of a webapp is really not sufficient for
|
||||
* indexing the various deployed ContextHandlers.
|
||||
*
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
private String getContextHandlerAppName(ContextHandler context)
|
||||
{
|
||||
String appName = context.getDisplayName();
|
||||
if (appName == null || appName.length() == 0 || getDeployedApps().containsKey(appName))
|
||||
{
|
||||
if (context instanceof WebAppContext)
|
||||
{
|
||||
appName = ((WebAppContext) context).getContextPath();
|
||||
if (getDeployedApps().containsKey(appName))
|
||||
{
|
||||
appName = "noDisplayName" + context.getClass().getSimpleName() + context.hashCode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
appName = "noDisplayName" + context.getClass().getSimpleName() + context.hashCode();
|
||||
}
|
||||
}
|
||||
return appName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default OSGiAppProvider constructed when none are defined in the
|
||||
* jetty.xml configuration.
|
||||
*/
|
||||
public OSGiAppProvider()
|
||||
{
|
||||
super(new Filter());
|
||||
((Filter) super._filenameFilter)._enclosedInstance = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default OSGiAppProvider constructed when none are defined in the
|
||||
* jetty.xml configuration.
|
||||
*
|
||||
* @param contextsDir
|
||||
*/
|
||||
public OSGiAppProvider(File contextsDir) throws IOException
|
||||
{
|
||||
this();
|
||||
setMonitoredDirResource(Resource.newResource(contextsDir.toURI()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ContextHandler that was created by WebappRegistractionHelper
|
||||
*
|
||||
* @see AppProvider
|
||||
*/
|
||||
public ContextHandler createContextHandler(App app) throws Exception
|
||||
{
|
||||
// return pre-created Context
|
||||
ContextHandler wah = app.getContextHandler();
|
||||
if (wah == null)
|
||||
{
|
||||
// for some reason it was not defined when the App was constructed.
|
||||
// we don't support this situation at this point.
|
||||
// once the WebAppRegistrationHelper is refactored, the code
|
||||
// that creates the ContextHandler will actually be here.
|
||||
throw new IllegalStateException("The App must be passed the " + "instance of the ContextHandler when it is constructed");
|
||||
}
|
||||
if (_configurationClasses != null && wah instanceof WebAppContext)
|
||||
{
|
||||
((WebAppContext) wah).setConfigurationClasses(_configurationClasses);
|
||||
}
|
||||
|
||||
if (_defaultsDescriptor != null)
|
||||
((WebAppContext) wah).setDefaultsDescriptor(_defaultsDescriptor);
|
||||
return app.getContextHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AppProvider
|
||||
*/
|
||||
@Override
|
||||
public void setDeploymentManager(DeploymentManager deploymentManager)
|
||||
{
|
||||
super.setDeploymentManager(deploymentManager);
|
||||
}
|
||||
|
||||
private static String getOriginId(Bundle contributor, String pathInBundle)
|
||||
{
|
||||
return contributor.getSymbolicName() + "-" + contributor.getVersion().toString() + (pathInBundle.startsWith("/") ? pathInBundle : "/" + pathInBundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @throws Exception
|
||||
*/
|
||||
public void addContext(Bundle contributor, String pathInBundle, ContextHandler context) throws Exception
|
||||
{
|
||||
addContext(getOriginId(contributor, pathInBundle), context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @throws Exception
|
||||
*/
|
||||
public void addContext(String originId, ContextHandler context) throws Exception
|
||||
{
|
||||
// TODO apply configuration specific to this provider
|
||||
if (context instanceof WebAppContext)
|
||||
{
|
||||
((WebAppContext) context).setExtractWAR(isExtract());
|
||||
}
|
||||
|
||||
// wrap context as an App
|
||||
App app = new App(getDeploymentManager(), this, originId, context);
|
||||
String appName = getContextHandlerAppName(context);
|
||||
getDeployedApps().put(appName, app);
|
||||
getDeploymentManager().addApp(app);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the scanner of the context files directory. If we find the
|
||||
* corresponding deployed App we reload it by returning the App. Otherwise
|
||||
* we return null and nothing happens: presumably the corresponding OSGi
|
||||
* webapp is not ready yet.
|
||||
*
|
||||
* @return the corresponding already deployed App so that it will be
|
||||
* reloaded. Otherwise returns null.
|
||||
*/
|
||||
@Override
|
||||
protected App createApp(String filename)
|
||||
{
|
||||
// find the corresponding bundle and ContextHandler or WebAppContext
|
||||
// and reload the corresponding App.
|
||||
// see the 2 pass of the refactoring of the WebAppRegistrationHelper.
|
||||
String name = getDeployedAppName(filename);
|
||||
if (name != null) { return getDeployedApps().get(name); }
|
||||
return null;
|
||||
}
|
||||
|
||||
public void removeContext(ContextHandler context) throws Exception
|
||||
{
|
||||
String appName = getContextHandlerAppName(context);
|
||||
App app = getDeployedApps().remove(context.getDisplayName());
|
||||
if (app == null)
|
||||
{
|
||||
// try harder to undeploy this context handler.
|
||||
// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=330098
|
||||
appName = null;
|
||||
for (Entry<String, App> deployedApp : getDeployedApps().entrySet())
|
||||
{
|
||||
if (deployedApp.getValue().getContextHandler() == context)
|
||||
{
|
||||
app = deployedApp.getValue();
|
||||
appName = deployedApp.getKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (appName != null)
|
||||
{
|
||||
getDeployedApps().remove(appName);
|
||||
}
|
||||
}
|
||||
if (app != null)
|
||||
{
|
||||
getDeploymentManager().removeApp(app);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* The context xml directory. In fact it is the directory watched by the
|
||||
* scanner.
|
||||
*/
|
||||
public File getContextXmlDirAsFile()
|
||||
{
|
||||
try
|
||||
{
|
||||
Resource monitoredDir = getMonitoredDirResource();
|
||||
if (monitoredDir == null) return null;
|
||||
return monitoredDir.getFile();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* The context xml directory. In fact it is the directory watched by the
|
||||
* scanner.
|
||||
*/
|
||||
public String getContextXmlDir()
|
||||
{
|
||||
try
|
||||
{
|
||||
Resource monitoredDir = getMonitoredDirResource();
|
||||
if (monitoredDir == null) return null;
|
||||
return monitoredDir.getFile().toURI().toString();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isExtract()
|
||||
{
|
||||
return _extractWars;
|
||||
}
|
||||
|
||||
public void setExtract(boolean extract)
|
||||
{
|
||||
_extractWars = extract;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true when this app provider locates osgi bundles and features in
|
||||
* its monitored directory and installs them. By default true if
|
||||
* there is a folder to monitor.
|
||||
*/
|
||||
public boolean isAutoInstallOSGiBundles()
|
||||
{
|
||||
return _autoInstallOSGiBundles;
|
||||
}
|
||||
|
||||
/**
|
||||
* <autoInstallOSGiBundles>true</autoInstallOSGiBundles>
|
||||
*
|
||||
* @param installingOSGiBundles
|
||||
*/
|
||||
public void setAutoInstallOSGiBundles(boolean installingOSGiBundles)
|
||||
{
|
||||
_autoInstallOSGiBundles = installingOSGiBundles;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Set the directory in which to look for context XML files.
|
||||
* <p>
|
||||
* If a webapp call "foo/" or "foo.war" is discovered in the monitored
|
||||
* directory, then the ContextXmlDir is examined to see if a foo.xml file
|
||||
* exists. If it does, then this deployer will not deploy the webapp and the
|
||||
* ContextProvider should be used to act on the foo.xml file.
|
||||
* </p>
|
||||
* <p>
|
||||
* Also if this directory contains some osgi bundles, it will install them.
|
||||
* </p>
|
||||
*
|
||||
* @see ContextProvider
|
||||
* @param contextsDir
|
||||
*/
|
||||
public void setContextXmlDir(String contextsDir)
|
||||
{
|
||||
setMonitoredDirName(contextsDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to install the OSGi bundles found in the monitored folder.
|
||||
*/
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if (isAutoInstallOSGiBundles())
|
||||
{
|
||||
if (getMonitoredDirResource() == null)
|
||||
{
|
||||
setAutoInstallOSGiBundles(false);
|
||||
LOG.info("Disable autoInstallOSGiBundles as there is not contexts folder to monitor.");
|
||||
}
|
||||
else
|
||||
{
|
||||
File scandir = null;
|
||||
try
|
||||
{
|
||||
scandir = getMonitoredDirResource().getFile();
|
||||
if (!scandir.exists() || !scandir.isDirectory())
|
||||
{
|
||||
setAutoInstallOSGiBundles(false);
|
||||
LOG.warn("Disable autoInstallOSGiBundles as the contexts folder '" + scandir.getAbsolutePath() + " does not exist.");
|
||||
scandir = null;
|
||||
}
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
setAutoInstallOSGiBundles(false);
|
||||
LOG.warn("Disable autoInstallOSGiBundles as the contexts folder '" + getMonitoredDirResource().getURI() + " does not exist.");
|
||||
scandir = null;
|
||||
}
|
||||
if (scandir != null)
|
||||
{
|
||||
for (File file : scandir.listFiles())
|
||||
{
|
||||
if (fileMightBeAnOSGiBundle(file))
|
||||
{
|
||||
installBundle(file, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
super.doStart();
|
||||
if (isAutoInstallOSGiBundles())
|
||||
{
|
||||
Scanner.ScanCycleListener scanCycleListner = new AutoStartWhenFrameworkHasCompleted(this);
|
||||
super.addScannerListener(scanCycleListner);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When the file is a jar or a folder, we look if it looks like an OSGi
|
||||
* bundle. In that case we install it and start it.
|
||||
* <p>
|
||||
* Really a simple trick to get going quickly with development.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
protected void fileAdded(String filename) throws Exception
|
||||
{
|
||||
File file = new File(filename);
|
||||
if (isAutoInstallOSGiBundles() && file.exists() && fileMightBeAnOSGiBundle(file))
|
||||
{
|
||||
installBundle(file, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.fileAdded(filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
private static boolean fileMightBeAnOSGiBundle(File file)
|
||||
{
|
||||
if (file.isDirectory())
|
||||
{
|
||||
if (new File(file, "META-INF/MANIFEST.MF").exists()) { return true; }
|
||||
}
|
||||
else if (file.getName().endsWith(".jar")) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fileChanged(String filename) throws Exception
|
||||
{
|
||||
File file = new File(filename);
|
||||
if (isAutoInstallOSGiBundles() && fileMightBeAnOSGiBundle(file))
|
||||
{
|
||||
updateBundle(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.fileChanged(filename);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fileRemoved(String filename) throws Exception
|
||||
{
|
||||
File file = new File(filename);
|
||||
if (isAutoInstallOSGiBundles() && fileMightBeAnOSGiBundle(file))
|
||||
{
|
||||
uninstallBundle(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.fileRemoved(filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bundle according to its location. In the version 1.6 of
|
||||
* org.osgi.framework, BundleContext.getBundle(String) is what we want.
|
||||
* However to support older versions of OSGi. We use our own local reference
|
||||
* mechanism.
|
||||
*
|
||||
* @param location
|
||||
* @return
|
||||
*/
|
||||
protected Bundle getBundle(BundleContext bc, String location)
|
||||
{
|
||||
// not available in older versions of OSGi:
|
||||
// return bc.getBundle(location);
|
||||
for (Bundle b : bc.getBundles())
|
||||
{
|
||||
if (b.getLocation().equals(location)) { return b; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected synchronized Bundle installBundle(File file, boolean start)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
BundleContext bc = JettyBootstrapActivator.getBundleContext();
|
||||
String location = file.toURI().toString();
|
||||
Bundle b = getBundle(bc, location);
|
||||
if (b == null)
|
||||
{
|
||||
b = bc.installBundle(location);
|
||||
}
|
||||
if (b == null)
|
||||
{
|
||||
// not sure we will ever be here,
|
||||
// most likely a BundleException was thrown
|
||||
LOG.warn("The file " + location + " is not an OSGi bundle.");
|
||||
return null;
|
||||
}
|
||||
if (start && b.getHeaders().get(Constants.FRAGMENT_HOST) == null)
|
||||
{
|
||||
// not a fragment, try to start it. if the framework has finished
|
||||
// auto-starting.
|
||||
if (!PackageAdminServiceTracker.INSTANCE.frameworkHasCompletedAutostarts())
|
||||
{
|
||||
if (_pendingBundlesToStart == null)
|
||||
{
|
||||
_pendingBundlesToStart = new HashSet<Bundle>();
|
||||
}
|
||||
_pendingBundlesToStart.add(b);
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
b.start();
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
catch (BundleException e)
|
||||
{
|
||||
LOG.warn("Unable to " + (start ? "start" : "install") + " the bundle " + file.getAbsolutePath(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void uninstallBundle(File file)
|
||||
{
|
||||
try
|
||||
{
|
||||
Bundle b = getBundle(JettyBootstrapActivator.getBundleContext(), file.toURI().toString());
|
||||
b.stop();
|
||||
b.uninstall();
|
||||
}
|
||||
catch (BundleException e)
|
||||
{
|
||||
LOG.warn("Unable to uninstall the bundle " + file.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateBundle(File file)
|
||||
{
|
||||
try
|
||||
{
|
||||
Bundle b = getBundle(JettyBootstrapActivator.getBundleContext(), file.toURI().toString());
|
||||
if (b == null)
|
||||
{
|
||||
installBundle(file, true);
|
||||
}
|
||||
else if (b.getState() == Bundle.ACTIVE)
|
||||
{
|
||||
b.update();
|
||||
}
|
||||
else
|
||||
{
|
||||
b.start();
|
||||
}
|
||||
}
|
||||
catch (BundleException e)
|
||||
{
|
||||
LOG.warn("Unable to update the bundle " + file.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* At the end of each scan, if there are some bundles to be started, look if the
|
||||
* framework has completed its autostart. In that case start those bundles.
|
||||
*/
|
||||
class AutoStartWhenFrameworkHasCompleted implements Scanner.ScanCycleListener
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AutoStartWhenFrameworkHasCompleted.class);
|
||||
|
||||
private final OSGiAppProvider _appProvider;
|
||||
|
||||
AutoStartWhenFrameworkHasCompleted(OSGiAppProvider appProvider)
|
||||
{
|
||||
_appProvider = appProvider;
|
||||
}
|
||||
|
||||
public void scanStarted(int cycle) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void scanEnded(int cycle) throws Exception
|
||||
{
|
||||
if (_appProvider._pendingBundlesToStart != null && PackageAdminServiceTracker.INSTANCE.frameworkHasCompletedAutostarts())
|
||||
{
|
||||
Iterator<Bundle> it = _appProvider._pendingBundlesToStart.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
Bundle b = it.next();
|
||||
if (b.getHeaders().get(Constants.FRAGMENT_HOST) != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
b.start();
|
||||
}
|
||||
catch (BundleException e)
|
||||
{
|
||||
LOG.warn("Unable to start the bundle " + b.getLocation(), e);
|
||||
}
|
||||
|
||||
}
|
||||
_appProvider._pendingBundlesToStart = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// ========================================================================
|
||||
// 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.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
package org.eclipse.jetty.osgi.boot;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.bindings.StandardDeployer;
|
||||
import org.eclipse.jetty.deploy.graph.Node;
|
||||
import org.eclipse.jetty.osgi.boot.utils.EventSender;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
|
||||
/**
|
||||
* OSGiDeployer
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class OSGiDeployer extends StandardDeployer
|
||||
{
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void processBinding(Node node, App app) throws Exception
|
||||
{
|
||||
//TODO how to NOT send this event if its not a webapp!
|
||||
EventSender.getInstance().send(EventSender.DEPLOYING_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath());
|
||||
try
|
||||
{
|
||||
super.processBinding(node,app);
|
||||
((AbstractOSGiApp)app).registerAsOSGiService();
|
||||
EventSender.getInstance().send(EventSender.DEPLOYED_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
EventSender.getInstance().send(EventSender.FAILED_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
// ========================================================================
|
||||
// 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 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);
|
||||
}
|
||||
}
|
|
@ -19,6 +19,38 @@ package org.eclipse.jetty.osgi.boot;
|
|||
*/
|
||||
public class OSGiServerConstants
|
||||
{
|
||||
/**
|
||||
* Usual system property used as the hostname for a typical jetty
|
||||
* configuration.
|
||||
*/
|
||||
public static final String JETTY_HOME = "jetty.home";
|
||||
|
||||
/**
|
||||
* System property to point to a bundle that embeds a jetty configuration
|
||||
* and that jetty configuration should be the default jetty server. First we
|
||||
* look for jetty.home. If we don't find it then we look for this property.
|
||||
*/
|
||||
public static final String JETTY_HOME_BUNDLE = "jetty.home.bundle";
|
||||
|
||||
/**
|
||||
* Usual system property used as the hostname for a typical jetty
|
||||
* configuration.
|
||||
*/
|
||||
public static final String JETTY_HOST = "jetty.host";
|
||||
|
||||
/**
|
||||
* Usual system property used as the port for http for a typical jetty
|
||||
* configuration.
|
||||
*/
|
||||
public static final String JETTY_PORT = "jetty.port";
|
||||
|
||||
/**
|
||||
* Usual system property used as the port for https for a typical jetty
|
||||
* configuration.
|
||||
*/
|
||||
public static final String JETTY_PORT_SSL = "jetty.port.ssl";
|
||||
|
||||
|
||||
//for managed jetty instances, name of the configuration parameters
|
||||
/**
|
||||
* PID of the jetty servers's ManagedFactory
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
// ========================================================================
|
||||
// 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.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
package org.eclipse.jetty.osgi.boot;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.bindings.StandardUndeployer;
|
||||
import org.eclipse.jetty.deploy.graph.Node;
|
||||
import org.eclipse.jetty.osgi.boot.utils.EventSender;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* OSGiUndeployer
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class OSGiUndeployer extends StandardUndeployer
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
public void processBinding(Node node, App app) throws Exception
|
||||
{
|
||||
EventSender.getInstance().send(EventSender.UNDEPLOYING_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath());
|
||||
super.processBinding(node,app);
|
||||
EventSender.getInstance().send(EventSender.UNDEPLOYED_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath());
|
||||
((AbstractOSGiApp)app).deregisterAsOSGiService();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,267 @@
|
|||
// ========================================================================
|
||||
// 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 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;
|
||||
}
|
||||
}
|
|
@ -19,6 +19,20 @@ package org.eclipse.jetty.osgi.boot;
|
|||
*/
|
||||
public class OSGiWebappConstants
|
||||
{
|
||||
/** service property osgi.web.symbolicname. See OSGi r4 */
|
||||
public static final String OSGI_WEB_SYMBOLICNAME = "osgi.web.symbolicname";
|
||||
|
||||
/** service property osgi.web.symbolicname. See OSGi r4 */
|
||||
public static final String OSGI_WEB_VERSION = "osgi.web.version";
|
||||
|
||||
/** service property osgi.web.contextpath. See OSGi r4 */
|
||||
public static final String OSGI_WEB_CONTEXTPATH = "osgi.web.contextpath";
|
||||
|
||||
/** See OSGi r4 p.427 */
|
||||
public static final String OSGI_BUNDLECONTEXT = "osgi-bundlecontext";
|
||||
|
||||
|
||||
|
||||
/** url scheme to deploy war file as bundled webapp */
|
||||
public static final String RFC66_WAR_URL_SCHEME = "war";
|
||||
|
||||
|
@ -55,32 +69,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";
|
||||
|
||||
public static final String JETTY_EXTRA_CLASSPATH = "Jetty-extraClasspath";
|
||||
|
||||
/** jetty context file path */
|
||||
/**
|
||||
* 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";
|
||||
|
||||
public static final String JETTY_WEB_XML_PATH = "Jetty-WebXmlFilePath";
|
||||
|
||||
/** defaultweb.xml file path */
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
@ -90,4 +132,14 @@ public class OSGiWebappConstants
|
|||
* Both the name of the manifest header and the name of the service property.
|
||||
*/
|
||||
public static final String SERVICE_PROP_REQUIRE_TLD_BUNDLE = REQUIRE_TLD_BUNDLE;
|
||||
|
||||
public static final String WATERMARK = "o.e.j.o.b.watermark";
|
||||
|
||||
/**
|
||||
* Set of extra dirs that must not be served by osgi webapps
|
||||
*/
|
||||
public static final String[] DEFAULT_PROTECTED_OSGI_TARGETS = {"/osgi-inf", "/osgi-opts"};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
package org.eclipse.jetty.osgi.boot;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
/**
|
||||
* ServiceContextProvider
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ServiceContextProvider extends AbstractContextProvider implements ServiceProvider
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractContextProvider.class);
|
||||
|
||||
private Map<ServiceReference, App> _serviceMap = new HashMap<ServiceReference, App>();
|
||||
|
||||
private ServiceRegistration _serviceRegForServices;
|
||||
|
||||
|
||||
/**
|
||||
* ServiceApp
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ServiceApp extends OSGiApp
|
||||
{
|
||||
public ServiceApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String contextFile, String originId)
|
||||
{
|
||||
super(manager, provider, bundle, properties, contextFile, originId);
|
||||
}
|
||||
|
||||
public ServiceApp(DeploymentManager manager, AppProvider provider, String originId, Bundle bundle, String contextFile)
|
||||
{
|
||||
super(manager, provider, originId, bundle, contextFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerAsOSGiService() throws Exception
|
||||
{
|
||||
//not applicable for apps that are already services
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deregisterAsOSGiService() throws Exception
|
||||
{
|
||||
//not applicable for apps that are already services
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ServiceContextProvider(ServerInstanceWrapper wrapper)
|
||||
{
|
||||
super(wrapper);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean serviceAdded (ServiceReference serviceRef, ContextHandler context)
|
||||
{
|
||||
if (context == null || serviceRef == null)
|
||||
return false;
|
||||
|
||||
String watermark = (String)serviceRef.getProperty(OSGiWebappConstants.WATERMARK);
|
||||
if (watermark != null && !"".equals(watermark))
|
||||
return false; //this service represents a contexthandler that has already been registered as a service by another of our deployers
|
||||
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(getServerInstanceWrapper().getParentClassLoaderForWebapps());
|
||||
try
|
||||
{
|
||||
//See if there is a context file to apply to this pre-made context
|
||||
String contextFile = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH);
|
||||
if (contextFile == null)
|
||||
contextFile = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH);
|
||||
|
||||
String[] keys = serviceRef.getPropertyKeys();
|
||||
Dictionary properties = new Hashtable<String, Object>();
|
||||
if (keys != null)
|
||||
{
|
||||
for (String key:keys)
|
||||
properties.put(key, serviceRef.getProperty(key));
|
||||
}
|
||||
Bundle bundle = serviceRef.getBundle();
|
||||
String originId = bundle.getSymbolicName() + "-" + bundle.getVersion().toString() + "-"+contextFile;
|
||||
ServiceApp app = new ServiceApp(getDeploymentManager(), this, bundle, properties, contextFile, originId);
|
||||
app.setHandler(context); //set the pre=made ContextHandler instance
|
||||
_serviceMap.put(serviceRef, app);
|
||||
getDeploymentManager().addApp(app);
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean serviceRemoved (ServiceReference serviceRef, ContextHandler context)
|
||||
{
|
||||
|
||||
if (context == null || serviceRef == null)
|
||||
return false;
|
||||
|
||||
String watermark = (String)serviceRef.getProperty(OSGiWebappConstants.WATERMARK);
|
||||
if (watermark != null && !"".equals(watermark))
|
||||
return false; //this service represents a contexthandler that will be deregistered as a service by another of our deployers
|
||||
|
||||
App app = _serviceMap.remove(serviceRef);
|
||||
if (app != null)
|
||||
{
|
||||
getDeploymentManager().removeApp(app);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
//register as an osgi service for deploying contexts defined in a bundle, advertising the name of the jetty Server instance we are related to
|
||||
Dictionary<String,String> properties = new Hashtable<String,String>();
|
||||
properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, getServerInstanceWrapper().getManagedServerName());
|
||||
|
||||
//register as an osgi service for deploying contexts, advertising the name of the jetty Server instance we are related to
|
||||
_serviceRegForServices = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(ServiceProvider.class.getName(), this, properties);
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
//unregister ourselves
|
||||
if (_serviceRegForServices != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_serviceRegForServices.unregister();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
super.doStop();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// ========================================================================
|
||||
// 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 org.eclipse.jetty.osgi.boot;
|
||||
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
public interface ServiceProvider
|
||||
{
|
||||
public boolean serviceAdded (ServiceReference ref, ContextHandler handler) throws Exception;
|
||||
|
||||
public boolean serviceRemoved (ServiceReference ref, ContextHandler handler) throws Exception;
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
package org.eclipse.jetty.osgi.boot;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.osgi.boot.utils.EventSender;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ServiceWebAppProvider
|
||||
*
|
||||
* Jetty Provider that knows how to deploy a WebApp that has been registered as an OSGi service.
|
||||
*
|
||||
*/
|
||||
public class ServiceWebAppProvider extends AbstractWebAppProvider implements ServiceProvider
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractWebAppProvider.class);
|
||||
|
||||
|
||||
/**
|
||||
* Map of ServiceRef to App. Used when it is an osgi service that is a WebAppContext.
|
||||
*/
|
||||
private Map<ServiceReference, App> _serviceMap = new HashMap<ServiceReference, App>();
|
||||
|
||||
private ServiceRegistration _serviceRegForServices;
|
||||
|
||||
|
||||
/**
|
||||
* ServiceApp
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ServiceApp extends OSGiApp
|
||||
{
|
||||
|
||||
public ServiceApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId)
|
||||
{
|
||||
super(manager, provider, bundle, properties, originId);
|
||||
}
|
||||
|
||||
public ServiceApp(DeploymentManager manager, AppProvider provider, Bundle bundle, String originId)
|
||||
{
|
||||
super(manager, provider, bundle, originId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerAsOSGiService() throws Exception
|
||||
{
|
||||
//not applicable for apps that are already services
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deregisterAsOSGiService() throws Exception
|
||||
{
|
||||
//not applicable for apps that are already services
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param wrapper
|
||||
*/
|
||||
public ServiceWebAppProvider (ServerInstanceWrapper wrapper)
|
||||
{
|
||||
super(wrapper);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* A webapp that was deployed as an osgi service has been added,
|
||||
* and we want to deploy it.
|
||||
*
|
||||
* @param context the webapp
|
||||
*/
|
||||
public boolean serviceAdded (ServiceReference serviceRef, ContextHandler context)
|
||||
{
|
||||
if (context == null || !(context instanceof WebAppContext))
|
||||
return false;
|
||||
|
||||
String watermark = (String)serviceRef.getProperty(OSGiWebappConstants.WATERMARK);
|
||||
if (watermark != null && !"".equals(watermark))
|
||||
return false; //this service represents a webapp that has already been registered as a service by another of our deployers
|
||||
|
||||
|
||||
WebAppContext webApp = (WebAppContext)context;
|
||||
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);
|
||||
if (contextPath == null)
|
||||
return false; //No context path
|
||||
|
||||
String base = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH);
|
||||
if (base == null)
|
||||
base = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_WAR);
|
||||
|
||||
if (base == null)
|
||||
return false; //No webapp base
|
||||
|
||||
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(getServerInstanceWrapper().getParentClassLoaderForWebapps());
|
||||
try
|
||||
{
|
||||
String originId = getOriginId(serviceRef.getBundle(), base);
|
||||
ServiceApp app = new ServiceApp(getDeploymentManager(), this, serviceRef.getBundle(), properties, originId);
|
||||
app.setContextPath(contextPath);
|
||||
app.setWebAppPath(base);
|
||||
app.setWebAppContext(webApp); //set the pre=made webapp instance
|
||||
_serviceMap.put(serviceRef, app);
|
||||
getDeploymentManager().addApp(app);
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param context the webapp
|
||||
*/
|
||||
public boolean serviceRemoved (ServiceReference serviceRef, ContextHandler context)
|
||||
{
|
||||
if (context == null || !(context instanceof WebAppContext))
|
||||
return false;
|
||||
|
||||
String watermark = (String)serviceRef.getProperty(OSGiWebappConstants.WATERMARK);
|
||||
if (watermark != null && !"".equals(watermark))
|
||||
return false; //this service represents a contexthandler that will be deregistered as a service by another of our deployers
|
||||
|
||||
App app = _serviceMap.remove(serviceRef);
|
||||
if (app != null)
|
||||
{
|
||||
getDeploymentManager().removeApp(app);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
|
||||
*/
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
//register as an osgi service for deploying bundles, advertising the name of the jetty Server instance we are related to
|
||||
Dictionary<String,String> properties = new Hashtable<String,String>();
|
||||
properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, getServerInstanceWrapper().getManagedServerName());
|
||||
|
||||
//register as an osgi service for deploying contexts (discovered as osgi services), advertising the name of the jetty Server instance we are related to
|
||||
_serviceRegForServices = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(ServiceProvider.class.getName(), this, properties);
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
|
||||
*/
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
//unregister ourselves
|
||||
if (_serviceRegForServices != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_serviceRegForServices.unregister();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
}
|
|
@ -24,6 +24,7 @@ import java.util.StringTokenizer;
|
|||
|
||||
import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
|
||||
import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
|
||||
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -32,6 +33,9 @@ import org.osgi.framework.Bundle;
|
|||
import org.osgi.framework.BundleContext;
|
||||
|
||||
/**
|
||||
* DefaultJettyAtJettyHomeHelper
|
||||
*
|
||||
*
|
||||
* Called by the {@link JettyBootstrapActivator} during the starting of the
|
||||
* bundle. If the system property 'jetty.home' is defined and points to a
|
||||
* folder, then setup the corresponding jetty server.
|
||||
|
@ -45,49 +49,20 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
* used to configure jetty. By default the value is 'etc/jetty.xml' when the
|
||||
* path is relative the file is resolved relatively to jettyhome.
|
||||
*/
|
||||
public static final String SYS_PROP_JETTY_ETC_FILES = OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS;
|
||||
public static final String JETTY_ETC_FILES = OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS;
|
||||
|
||||
/**
|
||||
* Usual system property used as the hostname for a typical jetty
|
||||
* configuration.
|
||||
*/
|
||||
public static final String SYS_PROP_JETTY_HOME = "jetty.home";
|
||||
|
||||
/**
|
||||
* System property to point to a bundle that embeds a jetty configuration
|
||||
* and that jetty configuration should be the default jetty server. First we
|
||||
* look for jetty.home. If we don't find it then we look for this property.
|
||||
*/
|
||||
public static final String SYS_PROP_JETTY_HOME_BUNDLE = "jetty.home.bundle";
|
||||
|
||||
/**
|
||||
* Usual system property used as the hostname for a typical jetty
|
||||
* configuration.
|
||||
*/
|
||||
public static final String SYS_PROP_JETTY_HOST = "jetty.host";
|
||||
|
||||
/**
|
||||
* Usual system property used as the port for http for a typical jetty
|
||||
* configuration.
|
||||
*/
|
||||
public static final String SYS_PROP_JETTY_PORT = "jetty.port";
|
||||
|
||||
/**
|
||||
* Usual system property used as the port for https for a typical jetty
|
||||
* configuration.
|
||||
*/
|
||||
public static final String SYS_PROP_JETTY_PORT_SSL = "jetty.port.ssl";
|
||||
|
||||
/**
|
||||
* Set of config files to apply to a jetty Server instance if none are supplied by SYS_PROP_JETTY_ETC_FILES
|
||||
*/
|
||||
public static final String DEFAULT_JETTY_ETC_FILES = "jetty.xml,jetty-selector.xml,jetty-deployer.xml";
|
||||
public static final String DEFAULT_JETTY_ETC_FILES = "etc/jetty.xml,etc/jetty-selector.xml,etc/jetty-deployer.xml";
|
||||
|
||||
/**
|
||||
* Default location within bundle of a jetty home dir.
|
||||
*/
|
||||
public static final String DEFAULT_JETTYHOME = "/jettyhome";
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Called by the JettyBootStrapActivator. If the system property jetty.home
|
||||
* is defined and points to a folder, creates a corresponding jetty
|
||||
|
@ -112,8 +87,8 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
*/
|
||||
public static void startJettyAtJettyHome(BundleContext bundleContext) throws Exception
|
||||
{
|
||||
String jettyHomeSysProp = System.getProperty(SYS_PROP_JETTY_HOME);
|
||||
String jettyHomeBundleSysProp = System.getProperty(SYS_PROP_JETTY_HOME_BUNDLE);
|
||||
String jettyHomeSysProp = System.getProperty(OSGiServerConstants.JETTY_HOME);
|
||||
String jettyHomeBundleSysProp = System.getProperty(OSGiServerConstants.JETTY_HOME_BUNDLE);
|
||||
File jettyHome = null;
|
||||
Bundle jettyHomeBundle = null;
|
||||
if (jettyHomeSysProp != null)
|
||||
|
@ -170,17 +145,18 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
|
||||
// these properties usually are the ones passed to this type of
|
||||
// configuration.
|
||||
setProperty(properties, SYS_PROP_JETTY_HOME, System.getProperty(SYS_PROP_JETTY_HOME));
|
||||
setProperty(properties, SYS_PROP_JETTY_HOST, System.getProperty(SYS_PROP_JETTY_HOST));
|
||||
setProperty(properties, SYS_PROP_JETTY_PORT, System.getProperty(SYS_PROP_JETTY_PORT));
|
||||
setProperty(properties, SYS_PROP_JETTY_PORT_SSL, System.getProperty(SYS_PROP_JETTY_PORT_SSL));
|
||||
setProperty(properties, OSGiServerConstants.JETTY_HOME, System.getProperty(OSGiServerConstants.JETTY_HOME));
|
||||
setProperty(properties, OSGiServerConstants.JETTY_HOST, System.getProperty(OSGiServerConstants.JETTY_HOST));
|
||||
setProperty(properties, OSGiServerConstants.JETTY_PORT, System.getProperty(OSGiServerConstants.JETTY_PORT));
|
||||
setProperty(properties, OSGiServerConstants.JETTY_PORT_SSL, System.getProperty(OSGiServerConstants.JETTY_PORT_SSL));
|
||||
|
||||
//register the Server instance as an OSGi service.
|
||||
bundleContext.registerService(Server.class.getName(), server, properties);
|
||||
// hookNestedConnectorToBridgeServlet(server);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Minimum setup for the location of the configuration files given a
|
||||
* jettyhome folder. Reads the system property jetty.etc.config.urls and
|
||||
|
@ -192,7 +168,7 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
*/
|
||||
private static String getJettyConfigurationURLs(File jettyhome)
|
||||
{
|
||||
String jettyetc = System.getProperty(SYS_PROP_JETTY_ETC_FILES, "etc/jetty.xml");
|
||||
String jettyetc = System.getProperty(JETTY_ETC_FILES, DEFAULT_JETTY_ETC_FILES);
|
||||
StringTokenizer tokenizer = new StringTokenizer(jettyetc, ";,", false);
|
||||
StringBuilder res = new StringBuilder();
|
||||
while (tokenizer.hasMoreTokens())
|
||||
|
@ -214,7 +190,9 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
}
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Minimum setup for the location of the configuration files given a
|
||||
* configuration embedded inside a bundle. Reads the system property
|
||||
|
@ -226,7 +204,7 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
*/
|
||||
private static String getJettyConfigurationURLs(Bundle configurationBundle)
|
||||
{
|
||||
String files = System.getProperty(SYS_PROP_JETTY_ETC_FILES, DEFAULT_JETTY_ETC_FILES);
|
||||
String files = System.getProperty(JETTY_ETC_FILES, DEFAULT_JETTY_ETC_FILES);
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(files, ";,", false);
|
||||
StringBuilder res = new StringBuilder();
|
||||
|
@ -242,36 +220,39 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
else
|
||||
{
|
||||
//relative file path
|
||||
Enumeration<URL> enUrls = BundleFileLocatorHelper.DEFAULT.findEntries(configurationBundle, etcFile);
|
||||
|
||||
Enumeration<URL> enUrls = BundleFileLocatorHelperFactory.getFactory().getHelper().findEntries(configurationBundle, etcFile);
|
||||
|
||||
// default for org.eclipse.osgi.boot where we look inside
|
||||
// jettyhome for the default embedded configuration.
|
||||
// default inside jettyhome. this way fragments to the bundle
|
||||
// can define their own configuration.
|
||||
if ((enUrls == null || !enUrls.hasMoreElements()))
|
||||
{
|
||||
String tmp = DEFAULT_JETTYHOME+"/etc/"+etcFile;
|
||||
enUrls = BundleFileLocatorHelper.DEFAULT.findEntries(configurationBundle, tmp);
|
||||
LOG.info("Configuring jetty with the default embedded configuration:" + "bundle: "
|
||||
String tmp = DEFAULT_JETTYHOME+etcFile;
|
||||
enUrls = BundleFileLocatorHelperFactory.getFactory().getHelper().findEntries(configurationBundle, tmp);
|
||||
LOG.info("Configuring jetty from bundle: "
|
||||
+ configurationBundle.getSymbolicName()
|
||||
+ " config: "+tmp);
|
||||
+ " with "+tmp);
|
||||
}
|
||||
if (enUrls == null || !enUrls.hasMoreElements())
|
||||
{
|
||||
LOG.warn("Unable to locate a jetty configuration file for " + etcFile);
|
||||
throw new IllegalStateException ("Unable to locate a jetty configuration file for " + etcFile);
|
||||
}
|
||||
if (enUrls != null)
|
||||
{
|
||||
while (enUrls.hasMoreElements())
|
||||
{
|
||||
appendToCommaSeparatedList(res, enUrls.nextElement().toString());
|
||||
URL url = BundleFileLocatorHelperFactory.getFactory().getHelper().getFileURL(enUrls.nextElement());
|
||||
appendToCommaSeparatedList(res, url.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private static void appendToCommaSeparatedList(StringBuilder buffer, String value)
|
||||
{
|
||||
if (buffer.length() != 0)
|
||||
|
@ -280,7 +261,9 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
}
|
||||
buffer.append(value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private static void setProperty(Dictionary<String,String> properties, String key, String value)
|
||||
{
|
||||
if (value != null)
|
||||
|
@ -288,7 +271,9 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
properties.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* recursively substitute the ${sysprop} by their actual system property.
|
||||
* ${sysprop,defaultvalue} will use 'defaultvalue' as the value if no
|
||||
|
|
|
@ -24,16 +24,24 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.eclipse.jetty.deploy.AppLifeCycle;
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.deploy.bindings.StandardStarter;
|
||||
import org.eclipse.jetty.deploy.bindings.StandardStopper;
|
||||
import org.eclipse.jetty.osgi.boot.BundleContextProvider;
|
||||
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.OSGiDeployer;
|
||||
import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
|
||||
import org.eclipse.jetty.osgi.boot.OSGiUndeployer;
|
||||
import org.eclipse.jetty.osgi.boot.ServiceContextProvider;
|
||||
import org.eclipse.jetty.osgi.boot.ServiceWebAppProvider;
|
||||
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;
|
||||
|
@ -59,6 +67,8 @@ public class ServerInstanceWrapper
|
|||
public static final String PROPERTY_THIS_JETTY_XML_FOLDER_URL = "this.jetty.xml.parent.folder.url";
|
||||
|
||||
private static Logger LOG = Log.getLogger(ServerInstanceWrapper.class.getName());
|
||||
|
||||
|
||||
|
||||
private final String _managedServerName;
|
||||
|
||||
|
@ -67,7 +77,7 @@ public class ServerInstanceWrapper
|
|||
*/
|
||||
private Server _server;
|
||||
|
||||
private ContextHandlerCollection _ctxtHandler;
|
||||
private ContextHandlerCollection _ctxtCollection;
|
||||
|
||||
/**
|
||||
* This is the class loader that should be the parent classloader of any
|
||||
|
@ -77,21 +87,22 @@ public class ServerInstanceWrapper
|
|||
private ClassLoader _commonParentClassLoaderForWebapps;
|
||||
|
||||
private DeploymentManager _deploymentManager;
|
||||
|
||||
private OSGiAppProvider _provider;
|
||||
|
||||
private WebBundleDeployerHelper _webBundleDeployerHelper;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ServerInstanceWrapper(String managedServerName)
|
||||
{
|
||||
_managedServerName = managedServerName;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getManagedServerName()
|
||||
{
|
||||
return _managedServerName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* The classloader that should be the parent classloader for each webapp
|
||||
* deployed on this server.
|
||||
|
@ -102,7 +113,9 @@ public class ServerInstanceWrapper
|
|||
{
|
||||
return _commonParentClassLoaderForWebapps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return The deployment manager registered on this server.
|
||||
*/
|
||||
|
@ -110,33 +123,28 @@ public class ServerInstanceWrapper
|
|||
{
|
||||
return _deploymentManager;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
public ContextHandlerCollection getContextHandlerCollection()
|
||||
{
|
||||
return _ctxtHandler;
|
||||
return _ctxtCollection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void start(Server server, Dictionary props) throws Exception
|
||||
{
|
||||
_server = server;
|
||||
|
@ -151,20 +159,20 @@ public class ServerInstanceWrapper
|
|||
List<File> shared = sharedURLs != null ? extractFiles(sharedURLs) : null;
|
||||
libExtClassLoader = LibExtClassLoaderHelper.createLibExtClassLoader(shared, null, server, JettyBootstrapActivator.class.getClassLoader());
|
||||
|
||||
if (LOG.isDebugEnabled()) LOG.debug("LibExtClassLoader = "+libExtClassLoader);
|
||||
|
||||
Thread.currentThread().setContextClassLoader(libExtClassLoader);
|
||||
|
||||
configure(server, props);
|
||||
|
||||
init();
|
||||
|
||||
// now that we have an app provider we can call the registration
|
||||
// customizer.
|
||||
|
||||
URL[] jarsWithTlds = getJarsWithTlds();
|
||||
_commonParentClassLoaderForWebapps = jarsWithTlds == null ? libExtClassLoader : new TldLocatableURLClassloader(libExtClassLoader, jarsWithTlds);
|
||||
|
||||
if (LOG.isDebugEnabled()) LOG.debug("common classloader = "+_commonParentClassLoaderForWebapps);
|
||||
|
||||
server.start();
|
||||
_webBundleDeployerHelper = new WebBundleDeployerHelper(this);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -187,7 +195,7 @@ public class ServerInstanceWrapper
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void stop()
|
||||
{
|
||||
try
|
||||
|
@ -202,7 +210,9 @@ public class ServerInstanceWrapper
|
|||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* TODO: right now only the jetty-jsp bundle is scanned for common taglibs.
|
||||
* Should support a way to plug more bundles that contain taglibs.
|
||||
|
@ -226,11 +236,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);
|
||||
|
@ -241,7 +259,9 @@ public class ServerInstanceWrapper
|
|||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void configure(Server server, Dictionary props) throws Exception
|
||||
{
|
||||
String jettyConfigurationUrls = (String) props.get(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS);
|
||||
|
@ -249,15 +269,20 @@ public class ServerInstanceWrapper
|
|||
if (jettyConfigurations == null || jettyConfigurations.isEmpty()) { return; }
|
||||
Map<String, Object> id_map = new HashMap<String, Object>();
|
||||
|
||||
//TODO need to put in the id of the server being configured
|
||||
//Put in a mapping for the id "Server" and the name of the server as the instance being configured
|
||||
id_map.put("Server", server);
|
||||
id_map.put((String)props.get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME), server);
|
||||
|
||||
Map<String, String> properties = new HashMap<String, String>();
|
||||
Enumeration<Object> en = props.keys();
|
||||
while (en.hasMoreElements())
|
||||
{
|
||||
Object key = en.nextElement();
|
||||
Object value = props.get(key);
|
||||
properties.put(String.valueOf(key), String.valueOf(value));
|
||||
String keyStr = String.valueOf(key);
|
||||
String valStr = String.valueOf(value);
|
||||
properties.put(keyStr, valStr);
|
||||
server.setAttribute(keyStr, valStr);
|
||||
}
|
||||
|
||||
for (URL jettyConfiguration : jettyConfigurations)
|
||||
|
@ -267,6 +292,11 @@ public class ServerInstanceWrapper
|
|||
{
|
||||
// Execute a Jetty configuration file
|
||||
Resource r = Resource.newResource(jettyConfiguration);
|
||||
if (!r.exists())
|
||||
{
|
||||
LOG.warn("File does not exist "+r);
|
||||
continue;
|
||||
}
|
||||
is = r.getInputStream();
|
||||
XmlConfiguration config = new XmlConfiguration(is);
|
||||
config.getIdMap().putAll(id_map);
|
||||
|
@ -309,45 +339,97 @@ public class ServerInstanceWrapper
|
|||
*
|
||||
* It is assumed the server has already been configured with the ContextHandlerCollection structure.
|
||||
*
|
||||
* The server must have an instance of OSGiAppProvider. If one is not provided, it is created.
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
// Get the context handler
|
||||
_ctxtHandler = (ContextHandlerCollection) _server.getChildHandlerByClass(ContextHandlerCollection.class);
|
||||
_ctxtCollection = (ContextHandlerCollection) _server.getChildHandlerByClass(ContextHandlerCollection.class);
|
||||
|
||||
// get a deployerManager
|
||||
if (_ctxtCollection == null)
|
||||
throw new IllegalStateException("ERROR: No ContextHandlerCollection configured in Server");
|
||||
|
||||
List<String> providerClassNames = new ArrayList<String>();
|
||||
|
||||
// get a deployerManager and some providers
|
||||
List<DeploymentManager> deployers = _server.getBeans(DeploymentManager.class);
|
||||
if (deployers != null && !deployers.isEmpty())
|
||||
{
|
||||
_deploymentManager = deployers.get(0);
|
||||
|
||||
|
||||
for (AppProvider provider : _deploymentManager.getAppProviders())
|
||||
{
|
||||
if (provider instanceof OSGiAppProvider)
|
||||
{
|
||||
_provider = (OSGiAppProvider) provider;
|
||||
break;
|
||||
}
|
||||
providerClassNames.add(provider.getClass().getName());
|
||||
}
|
||||
if (_provider == null)
|
||||
}
|
||||
else
|
||||
{
|
||||
//add some kind of default
|
||||
_deploymentManager = new DeploymentManager();
|
||||
_deploymentManager.setContexts(_ctxtCollection);
|
||||
_server.addBean(_deploymentManager);
|
||||
}
|
||||
|
||||
_deploymentManager.setUseStandardBindings(false);
|
||||
List<AppLifeCycle.Binding> deploymentLifeCycleBindings = new ArrayList<AppLifeCycle.Binding>();
|
||||
deploymentLifeCycleBindings.add(new OSGiDeployer());
|
||||
deploymentLifeCycleBindings.add(new StandardStarter());
|
||||
deploymentLifeCycleBindings.add(new StandardStopper());
|
||||
deploymentLifeCycleBindings.add(new OSGiUndeployer());
|
||||
_deploymentManager.setLifeCycleBindings(deploymentLifeCycleBindings);
|
||||
|
||||
if (!providerClassNames.contains(BundleWebAppProvider.class.getName()))
|
||||
{
|
||||
// create it on the fly with reasonable default values.
|
||||
try
|
||||
{
|
||||
// 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()));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
_deploymentManager.addAppProvider(_provider);
|
||||
BundleWebAppProvider webAppProvider = new BundleWebAppProvider(this);
|
||||
_deploymentManager.addAppProvider(webAppProvider);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (_ctxtHandler == null || _provider == null) throw new IllegalStateException("ERROR: No ContextHandlerCollection or OSGiAppProvider configured");
|
||||
if (!providerClassNames.contains(ServiceWebAppProvider.class.getName()))
|
||||
{
|
||||
// create it on the fly with reasonable default values.
|
||||
try
|
||||
{
|
||||
ServiceWebAppProvider webAppProvider = new ServiceWebAppProvider(this);
|
||||
_deploymentManager.addAppProvider(webAppProvider);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!providerClassNames.contains(BundleContextProvider.class.getName()))
|
||||
{
|
||||
try
|
||||
{
|
||||
BundleContextProvider contextProvider = new BundleContextProvider(this);
|
||||
_deploymentManager.addAppProvider(contextProvider);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!providerClassNames.contains(ServiceContextProvider.class.getName()))
|
||||
{
|
||||
try
|
||||
{
|
||||
ServiceContextProvider contextProvider = new ServiceContextProvider(this);
|
||||
_deploymentManager.addAppProvider(contextProvider);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -374,10 +456,6 @@ public class ServerInstanceWrapper
|
|||
return new File(jettyHome, "/contexts");
|
||||
}
|
||||
|
||||
File getOSGiContextsHome()
|
||||
{
|
||||
return _provider.getContextXmlDirAsFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the urls in this string.
|
||||
|
@ -391,7 +469,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 +493,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);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
// ========================================================================
|
||||
// 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 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -14,12 +14,18 @@ package org.eclipse.jetty.osgi.boot.internal.webapp;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
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.ServiceProvider;
|
||||
import org.eclipse.jetty.osgi.boot.internal.serverfactory.DefaultJettyAtJettyHomeHelper;
|
||||
import org.eclipse.jetty.osgi.boot.internal.serverfactory.IManagedJettyServerRegistry;
|
||||
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
|
@ -34,107 +40,83 @@ 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
|
||||
* corresponding webapp is actually not configured then we go and register it.
|
||||
* <p>
|
||||
* The idea is to always go through this class when we deploy a new webapp on
|
||||
* jetty.
|
||||
* </p>
|
||||
* <p>
|
||||
* We are exposing each web-application as an OSGi service. This lets us update
|
||||
* the webapps and stop/start them directly at the OSGi layer. It also give us
|
||||
* many ways to declare those services: Declarative Services for example. <br/>
|
||||
* It is a bit different from the way the HttpService works where we would have
|
||||
* a WebappService and we woud register a webapp onto it. <br/>
|
||||
* It does not go against RFC-66 nor does it prevent us from supporting the
|
||||
* WebappContainer semantics.
|
||||
* </p>
|
||||
* JettyContextHandlerServiceTracker
|
||||
*
|
||||
* When a {@link ContextHandler} is activated as an osgi service we find a jetty deployer
|
||||
* for it. The ContextHandler could be either a WebAppContext or any other derivative of
|
||||
* ContextHandler.
|
||||
*
|
||||
* ContextHandlers and WebApps can also be deployed into jetty without creating them as
|
||||
* osgi services. Instead, they can be deployed via manifest headers inside bundles. See
|
||||
* {@link WebBundleTrackerCustomizer}.
|
||||
*/
|
||||
public class JettyContextHandlerServiceTracker implements ServiceListener
|
||||
{
|
||||
private static Logger __logger = Log.getLogger(WebBundleDeployerHelper.class.getName());
|
||||
|
||||
/** New style: ability to manage multiple jetty instances */
|
||||
private final IManagedJettyServerRegistry _registry;
|
||||
|
||||
/** The context-handler to deactivate indexed by context handler */
|
||||
private Map<ServiceReference, ContextHandler> _indexByServiceReference = new HashMap<ServiceReference, ContextHandler>();
|
||||
|
||||
/**
|
||||
* The index is the bundle-symbolic-name/path/to/context/file when there is
|
||||
* such thing
|
||||
*/
|
||||
private Map<String, ServiceReference> _indexByContextFile = new HashMap<String, ServiceReference>();
|
||||
|
||||
/** in charge of detecting changes in the osgi contexts home folder. */
|
||||
private Scanner _scanner;
|
||||
private static Logger LOG = Log.getLogger(JettyContextHandlerServiceTracker.class);
|
||||
|
||||
public static final String FILTER = "(objectclass=" + ServiceProvider.class.getName() + ")";
|
||||
|
||||
|
||||
//track all instances of deployers of webapps as bundles
|
||||
ServiceTracker _serviceTracker;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param registry
|
||||
*/
|
||||
public JettyContextHandlerServiceTracker(IManagedJettyServerRegistry registry) throws Exception
|
||||
public JettyContextHandlerServiceTracker() 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
|
||||
{
|
||||
if (_scanner != null)
|
||||
{
|
||||
_scanner.stop();
|
||||
}
|
||||
// the class that created the server is also in charge of stopping it.
|
||||
// nothing to stop in the WebappRegistrationHelper
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param contextHome Parent folder where the context files can override the
|
||||
* context files defined in the web bundles: equivalent to the
|
||||
* contexts folder in a traditional jetty installation. when
|
||||
* null, just do nothing.
|
||||
* @param managedServerName
|
||||
* @return
|
||||
*/
|
||||
protected void setupContextHomeScanner(File contextHome) throws IOException
|
||||
public Map<ServiceReference, ServiceProvider> getDeployers(String managedServerName)
|
||||
{
|
||||
if (contextHome == null) { return; }
|
||||
final String osgiContextHomeFolderCanonicalPath = contextHome.getCanonicalPath();
|
||||
_scanner = new Scanner();
|
||||
_scanner.setRecursive(true);
|
||||
_scanner.setReportExistingFilesOnStartup(false);
|
||||
_scanner.addListener(new Scanner.DiscreteListener()
|
||||
if (managedServerName == null)
|
||||
managedServerName = OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME;
|
||||
|
||||
Map<ServiceReference, ServiceProvider> candidates = new HashMap<ServiceReference, ServiceProvider>();
|
||||
|
||||
ServiceReference[] references = _serviceTracker.getServiceReferences();
|
||||
if (references != null)
|
||||
{
|
||||
public void fileAdded(String filename) throws Exception
|
||||
for (ServiceReference ref:references)
|
||||
{
|
||||
// adding a file does not create a new app,
|
||||
// it just reloads it with the new custom file.
|
||||
// well, if the file does not define a context handler,
|
||||
// then in fact it does remove it.
|
||||
reloadJettyContextHandler(filename, osgiContextHomeFolderCanonicalPath);
|
||||
String name = (String)ref.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
if (managedServerName.equalsIgnoreCase(name))
|
||||
{
|
||||
ServiceProvider candidate = (ServiceProvider)_serviceTracker.getService(ref);
|
||||
if (candidate != null)
|
||||
candidates.put(ref, candidate);
|
||||
}
|
||||
}
|
||||
|
||||
public void fileChanged(String filename) throws Exception
|
||||
{
|
||||
reloadJettyContextHandler(filename, osgiContextHomeFolderCanonicalPath);
|
||||
}
|
||||
|
||||
public void fileRemoved(String filename) throws Exception
|
||||
{
|
||||
// removing a file does not remove the app:
|
||||
// it just goes back to the default embedded in the bundle.
|
||||
// well, if there was no default then it does remove it.
|
||||
reloadJettyContextHandler(filename, osgiContextHomeFolderCanonicalPath);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
return candidates;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Receives notification that a service has had a lifecycle change.
|
||||
*
|
||||
* @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,16 +125,32 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
|
|||
case ServiceEvent.MODIFIED:
|
||||
case ServiceEvent.UNREGISTERING:
|
||||
{
|
||||
ContextHandler ctxtHandler = unregisterInIndex(ev.getServiceReference());
|
||||
if (ctxtHandler != null && !ctxtHandler.isStopped())
|
||||
BundleContext context = FrameworkUtil.getBundle(JettyBootstrapActivator.class).getBundleContext();
|
||||
ContextHandler contextHandler = (ContextHandler) context.getService(sr);
|
||||
|
||||
//if this was not a service that another of our deployers may have deployed (in which case they will undeploy it)
|
||||
String watermark = (String)sr.getProperty(OSGiWebappConstants.WATERMARK);
|
||||
if (watermark != null && !"".equals(watermark))
|
||||
{
|
||||
try
|
||||
//Get a jetty deployer targetted to the named server instance, or the default one if not named
|
||||
String serverName = (String)sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
Map<ServiceReference, ServiceProvider> candidates = getDeployers(serverName);
|
||||
if (candidates != null)
|
||||
{
|
||||
getWebBundleDeployerHelp(sr).unregister(ctxtHandler);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
__logger.warn(e);
|
||||
boolean removed = false;
|
||||
Iterator<Entry<ServiceReference, ServiceProvider>> itor = candidates.entrySet().iterator();
|
||||
while (!removed && itor.hasNext())
|
||||
{
|
||||
Entry<ServiceReference, ServiceProvider> e = itor.next();
|
||||
try
|
||||
{
|
||||
removed = e.getValue().serviceRemoved(sr, contextHandler);
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
LOG.warn("Error undeploying service representing jetty context ", x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,210 +173,34 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
|
|||
// is configured elsewhere.
|
||||
return;
|
||||
}
|
||||
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.
|
||||
// that case is identified by the fact that the contextFilePath
|
||||
// is not null
|
||||
// in that case we must use the register context methods.
|
||||
String watermark = (String)sr.getProperty(OSGiWebappConstants.WATERMARK);
|
||||
if (watermark != null && !"".equals(watermark))
|
||||
return; //another of our deployers is responsible for handling service registrations for this context
|
||||
|
||||
//Get a jetty deployer targetted to the named server instance, or the default one if not named
|
||||
String serverName = (String)sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
Map<ServiceReference, ServiceProvider> candidates = getDeployers(serverName);
|
||||
if (candidates != null)
|
||||
{
|
||||
WebAppContext webapp = (WebAppContext) contextHandler;
|
||||
String contextPath = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH);
|
||||
if (contextPath == null)
|
||||
boolean added = false;
|
||||
Iterator<Entry<ServiceReference, ServiceProvider>> itor = candidates.entrySet().iterator();
|
||||
while (!added && itor.hasNext())
|
||||
{
|
||||
contextPath = webapp.getContextPath();
|
||||
}
|
||||
String webXmlPath = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_WEB_XML_PATH);
|
||||
if (webXmlPath == null)
|
||||
{
|
||||
webXmlPath = webapp.getDescriptor();
|
||||
}
|
||||
String defaultWebXmlPath = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_DEFAULT_WEB_XML_PATH);
|
||||
if (defaultWebXmlPath == null)
|
||||
{
|
||||
String jettyHome = System.getProperty(DefaultJettyAtJettyHomeHelper.SYS_PROP_JETTY_HOME);
|
||||
if (jettyHome != null)
|
||||
Entry<ServiceReference, ServiceProvider> e = itor.next();
|
||||
try
|
||||
{
|
||||
File etc = new File(jettyHome, "etc");
|
||||
if (etc.exists() && etc.isDirectory())
|
||||
{
|
||||
File webDefault = new File(etc, "webdefault.xml");
|
||||
if (webDefault.exists())
|
||||
defaultWebXmlPath = webDefault.getAbsolutePath();
|
||||
else
|
||||
defaultWebXmlPath = webapp.getDefaultsDescriptor();
|
||||
}
|
||||
else
|
||||
defaultWebXmlPath = webapp.getDefaultsDescriptor();
|
||||
added = e.getValue().serviceAdded(sr, contextHandler);
|
||||
if (added && LOG.isDebugEnabled())
|
||||
LOG.debug("Provider "+e.getValue()+" deployed "+contextHandler);
|
||||
}
|
||||
}
|
||||
String war = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_WAR);
|
||||
try
|
||||
{
|
||||
IWebBundleDeployerHelper deployerHelper = getWebBundleDeployerHelp(sr);
|
||||
if (deployerHelper == null)
|
||||
catch (Exception x)
|
||||
{
|
||||
|
||||
LOG.warn("Error deploying service representing jetty context", x);
|
||||
}
|
||||
else
|
||||
{
|
||||
WebAppContext handler = deployerHelper.registerWebapplication(contributor,
|
||||
war,
|
||||
contextPath,
|
||||
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_EXTRA_CLASSPATH),
|
||||
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE),
|
||||
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE),
|
||||
webXmlPath, defaultWebXmlPath, webapp);
|
||||
if (handler != null)
|
||||
{
|
||||
registerInIndex(handler, sr);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
__logger.warn(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// consider this just an empty skeleton:
|
||||
if (contextFilePath == null) { throw new IllegalArgumentException("the property contextFilePath is required"); }
|
||||
try
|
||||
{
|
||||
IWebBundleDeployerHelper deployerHelper = getWebBundleDeployerHelp(sr);
|
||||
if (deployerHelper == null)
|
||||
{
|
||||
// more warnings?
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Boolean.TRUE.toString().equals(sr.getProperty(IWebBundleDeployerHelper.INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE)))
|
||||
{
|
||||
contextHandler = null;
|
||||
}
|
||||
ContextHandler handler = deployerHelper.registerContext(contributor,
|
||||
contextFilePath,
|
||||
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_EXTRA_CLASSPATH),
|
||||
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE),
|
||||
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE),
|
||||
contextHandler);
|
||||
if (handler != null)
|
||||
{
|
||||
registerInIndex(handler, sr);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
__logger.warn(e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void registerInIndex(ContextHandler handler, ServiceReference sr)
|
||||
{
|
||||
_indexByServiceReference.put(sr, handler);
|
||||
String key = getSymbolicNameAndContextFileKey(sr);
|
||||
if (key != null)
|
||||
{
|
||||
_indexByContextFile.put(key, sr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ContextHandler to stop.
|
||||
*
|
||||
* @param reg
|
||||
* @return the ContextHandler to stop.
|
||||
*/
|
||||
private ContextHandler unregisterInIndex(ServiceReference sr)
|
||||
{
|
||||
ContextHandler handler = _indexByServiceReference.remove(sr);
|
||||
String key = getSymbolicNameAndContextFileKey(sr);
|
||||
if (key != null)
|
||||
{
|
||||
_indexByContextFile.remove(key);
|
||||
}
|
||||
if (handler == null)
|
||||
{
|
||||
// a warning?
|
||||
return null;
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sr
|
||||
* @return The key for a context file within the osgi contexts home folder.
|
||||
*/
|
||||
private String getSymbolicNameAndContextFileKey(ServiceReference sr)
|
||||
{
|
||||
String contextFilePath = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH);
|
||||
if (contextFilePath != null) { return sr.getBundle().getSymbolicName() + "/" + contextFilePath; }
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the scanner when one of the context files is changed.
|
||||
*
|
||||
* @param contextFileFully
|
||||
*/
|
||||
public void reloadJettyContextHandler(String canonicalNameOfFileChanged, String osgiContextHomeFolderCanonicalPath)
|
||||
{
|
||||
String key = getNormalizedRelativePath(canonicalNameOfFileChanged, osgiContextHomeFolderCanonicalPath);
|
||||
if (key == null) { return; }
|
||||
ServiceReference sr = _indexByContextFile.get(key);
|
||||
if (sr == null)
|
||||
{
|
||||
// nothing to do?
|
||||
return;
|
||||
}
|
||||
serviceChanged(new ServiceEvent(ServiceEvent.MODIFIED, sr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param canFilename
|
||||
* @return
|
||||
*/
|
||||
private String getNormalizedRelativePath(String canFilename, String osgiContextHomeFolderCanonicalPath)
|
||||
{
|
||||
if (!canFilename.startsWith(osgiContextHomeFolderCanonicalPath))
|
||||
{
|
||||
// why are we here: this does not look like a child of the osgi
|
||||
// contexts home.
|
||||
// warning?
|
||||
return null;
|
||||
}
|
||||
return canFilename.substring(osgiContextHomeFolderCanonicalPath.length()).replace('\\', '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The server on which this webapp is meant to be deployed
|
||||
*/
|
||||
private ServerInstanceWrapper getServerInstanceWrapper(String managedServerName)
|
||||
{
|
||||
if (_registry == null) { return null; }
|
||||
if (managedServerName == null)
|
||||
{
|
||||
managedServerName = OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME;
|
||||
}
|
||||
ServerInstanceWrapper wrapper = _registry.getServerInstanceWrapper(managedServerName);
|
||||
// System.err.println("Returning " + managedServerName + " = " +
|
||||
// wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
private IWebBundleDeployerHelper getWebBundleDeployerHelp(ServiceReference sr)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 "this.bundle.install" 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();
|
||||
}
|
||||
}
|
|
@ -12,46 +12,61 @@
|
|||
// ========================================================================
|
||||
package org.eclipse.jetty.osgi.boot.internal.webapp;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Dictionary;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
|
||||
import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
|
||||
import org.eclipse.jetty.osgi.boot.BundleProvider;
|
||||
import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
|
||||
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
|
||||
* manifest.
|
||||
* <p>
|
||||
* Those headers will define a new WebApplication:
|
||||
* <ul>
|
||||
* <li>Web-ContextPath</li>
|
||||
* <li>Jetty-WarFolderPath</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* Those headers will define a new app started via a jetty-context or a list of
|
||||
* them. ',' column is the separator between the various context files.
|
||||
* <ul>
|
||||
* <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.
|
||||
* WebBundleTrackerCustomizer
|
||||
*
|
||||
*
|
||||
* Support bundles that declare a webpp or context directly through headers in their
|
||||
* manifest. They will be deployed to the default jetty Server instance.
|
||||
*
|
||||
* If you wish to deploy a context or webapp to a different jetty Server instance,
|
||||
* register your context/webapp as an osgi service, and set the property OSGiServerConstants.MANAGED_JETTY_SERVER_NAME
|
||||
* with the name of the Server instance you wish to depoy to.
|
||||
*
|
||||
* @author hmalphettes
|
||||
*/
|
||||
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=" + BundleProvider.class.getName() + ")"+
|
||||
"("+OSGiServerConstants.MANAGED_JETTY_SERVER_NAME+"="+OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME+"))";
|
||||
|
||||
private ServiceTracker _serviceTracker;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public WebBundleTrackerCustomizer ()
|
||||
throws Exception
|
||||
{
|
||||
Bundle myBundle = FrameworkUtil.getBundle(this.getClass());
|
||||
|
||||
//track all instances of deployers of webapps/contexts 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 +91,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)
|
||||
{
|
||||
|
@ -91,6 +105,8 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* A bundle tracked by the <code>BundleTracker</code> has been modified.
|
||||
*
|
||||
|
@ -118,6 +134,8 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* A bundle tracked by the <code>BundleTracker</code> has been removed.
|
||||
*
|
||||
|
@ -136,129 +154,64 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer
|
|||
unregister(bundle);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param bundle
|
||||
* @return true if this bundle in indeed a web-bundle.
|
||||
*/
|
||||
private boolean register(Bundle bundle)
|
||||
{
|
||||
Dictionary<?, ?> dic = bundle.getHeaders();
|
||||
String warFolderRelativePath = (String) dic.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH);
|
||||
if (warFolderRelativePath != null)
|
||||
if (bundle == null)
|
||||
return false;
|
||||
|
||||
//It might be a bundle that we can deploy to our default jetty server instance
|
||||
boolean deployed = false;
|
||||
Object[] deployers = _serviceTracker.getServices();
|
||||
if (deployers != null)
|
||||
{
|
||||
String contextPath = getWebContextPath(bundle, dic, false);
|
||||
if (contextPath == null || !contextPath.startsWith("/"))
|
||||
int i=0;
|
||||
while (!deployed && i<deployers.length)
|
||||
{
|
||||
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.");
|
||||
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.
|
||||
|
||||
BundleProvider p = (BundleProvider)deployers[i];
|
||||
try
|
||||
{
|
||||
deployed = p.bundleAdded(bundle);
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
LOG.warn("Error deploying bundle for jetty context", x);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else if (dic.get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH) != null)
|
||||
|
||||
return deployed;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param bundle
|
||||
*/
|
||||
private void unregister(Bundle bundle)
|
||||
{
|
||||
Object[] deployers = _serviceTracker.getServices();
|
||||
boolean undeployed = false;
|
||||
if (deployers != null)
|
||||
{
|
||||
String contextFileRelativePath = (String) dic.get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH);
|
||||
if (contextFileRelativePath == null)
|
||||
{
|
||||
// nothing to register here.
|
||||
return false;
|
||||
}
|
||||
// support for multiple webapps in the same bundle:
|
||||
String[] pathes = contextFileRelativePath.split(",;");
|
||||
for (String path : pathes)
|
||||
int i=0;
|
||||
while (!undeployed && i<deployers.length)
|
||||
{
|
||||
try
|
||||
{
|
||||
JettyBootstrapActivator.registerContext(bundle, path.trim());
|
||||
undeployed = ((BundleProvider)deployers[i++]).bundleRemoved(bundle);
|
||||
}
|
||||
catch (Throwable e)
|
||||
catch (Exception x)
|
||||
{
|
||||
LOG.warn(e);
|
||||
LOG.warn("Error undeploying bundle for jetty context", x);
|
||||
}
|
||||
}
|
||||
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.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
// ========================================================================
|
||||
// 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 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -83,5 +83,31 @@ public interface BundleFileLocatorHelper
|
|||
* @return null or all the entries found for that path.
|
||||
*/
|
||||
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);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
// ========================================================================
|
||||
// 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 org.eclipse.jetty.osgi.boot.utils;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import javax.security.auth.login.FailedLoginException;
|
||||
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.service.event.Event;
|
||||
import org.osgi.service.event.EventAdmin;
|
||||
|
||||
public class EventSender
|
||||
{
|
||||
//OSGi Event Admin events for webapps
|
||||
public static final String DEPLOYING_EVENT = "org/osgi/service/web/DEPLOYING";
|
||||
public static final String DEPLOYED_EVENT = "org/osgi/service/web/DEPLOYED";
|
||||
public static final String UNDEPLOYING_EVENT = "org/osgi/service/web/UNDEPLOYING";
|
||||
public static final String UNDEPLOYED_EVENT = "org/osgi/service/web/UNDEPLOYED";
|
||||
public static final String FAILED_EVENT = "org/osgi/service/web/FAILED";
|
||||
|
||||
|
||||
private static final EventSender __instance = new EventSender();
|
||||
private Bundle _myBundle;
|
||||
private EventAdmin _eventAdmin;
|
||||
|
||||
private EventSender ()
|
||||
{
|
||||
_myBundle = FrameworkUtil.getBundle(EventSender.class);
|
||||
ServiceReference ref = _myBundle.getBundleContext().getServiceReference(EventAdmin.class.getName());
|
||||
if (ref != null)
|
||||
_eventAdmin = (EventAdmin)_myBundle.getBundleContext().getService(ref);
|
||||
}
|
||||
|
||||
|
||||
public static EventSender getInstance()
|
||||
{
|
||||
return __instance;
|
||||
}
|
||||
|
||||
public void send (String topic, Bundle wab, String contextPath)
|
||||
{
|
||||
if (topic==null || wab==null || contextPath==null)
|
||||
return;
|
||||
|
||||
send(topic, wab, contextPath, null);
|
||||
}
|
||||
|
||||
|
||||
public void send (String topic, Bundle wab, String contextPath, Exception ex)
|
||||
{
|
||||
if (_eventAdmin == null)
|
||||
return;
|
||||
|
||||
Dictionary<String,Object> props = new Hashtable<String,Object>();
|
||||
props.put("bundle.symbolicName", wab.getSymbolicName());
|
||||
props.put("bundle.id", wab.getBundleId());
|
||||
props.put("bundle", wab);
|
||||
props.put("bundle.version", wab.getVersion());
|
||||
props.put("context.path", contextPath);
|
||||
props.put("timestamp", System.currentTimeMillis());
|
||||
props.put("extender.bundle", _myBundle);
|
||||
props.put("extender.bundle.symbolicName", _myBundle.getSymbolicName());
|
||||
props.put("extender.bundle.id", _myBundle.getBundleId());
|
||||
props.put("extender.bundle.version", _myBundle.getVersion());
|
||||
|
||||
if (FAILED_EVENT.equalsIgnoreCase(topic) && ex != null)
|
||||
props.put("exception", ex);
|
||||
|
||||
_eventAdmin.sendEvent(new Event(topic, props));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
// ========================================================================
|
||||
// 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 org.eclipse.jetty.osgi.boot.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
/**
|
||||
* OSGiClassLoader
|
||||
*
|
||||
* Class loader that is aware of a bundle. Similar to WebAppClassLoader from Jetty
|
||||
* and the OSGiWebAppClassLoader, but works without webapps.
|
||||
*/
|
||||
public class OSGiClassLoader extends URLClassLoader
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(OSGiClassLoader.class);
|
||||
|
||||
|
||||
private Bundle _bundle;
|
||||
private ClassLoader _osgiBundleClassLoader;
|
||||
private boolean _lookInOsgiFirst = true;
|
||||
private ClassLoader _parent;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public OSGiClassLoader(ClassLoader parent, Bundle bundle)
|
||||
{
|
||||
super(new URL[]{}, parent);
|
||||
_parent = getParent();
|
||||
_bundle = bundle;
|
||||
_osgiBundleClassLoader = BundleClassLoaderHelperFactory.getFactory().getHelper().getBundleClassLoader(_bundle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Get a resource from the classloader
|
||||
*
|
||||
* Copied from WebAppClassLoader
|
||||
*/
|
||||
public URL getResource(String name)
|
||||
{
|
||||
URL url= null;
|
||||
boolean tried_parent= false;
|
||||
|
||||
|
||||
if (_parent!=null && !_lookInOsgiFirst)
|
||||
{
|
||||
tried_parent= true;
|
||||
|
||||
if (_parent!=null)
|
||||
url= _parent.getResource(name);
|
||||
}
|
||||
|
||||
if (url == null)
|
||||
{
|
||||
|
||||
url = _osgiBundleClassLoader.getResource(name);
|
||||
|
||||
if (url == null && name.startsWith("/"))
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("HACK leading / off " + name);
|
||||
|
||||
url = _osgiBundleClassLoader.getResource(name.substring(1));
|
||||
}
|
||||
}
|
||||
|
||||
if (url == null && !tried_parent)
|
||||
{
|
||||
if (_parent!=null)
|
||||
url= _parent.getResource(name);
|
||||
}
|
||||
|
||||
if (url != null)
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("getResource("+name+")=" + url);
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
return loadClass(name, false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
|
||||
{
|
||||
Class<?> c = findLoadedClass(name);
|
||||
ClassNotFoundException ex= null;
|
||||
boolean tried_parent= false;
|
||||
|
||||
if (c == null && _parent!=null && !_lookInOsgiFirst)
|
||||
{
|
||||
tried_parent= true;
|
||||
try
|
||||
{
|
||||
c= _parent.loadClass(name);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("loaded " + c);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
ex= e;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
c= this.findClass(name);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
ex= e;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == null && _parent!=null && !tried_parent)
|
||||
c = _parent.loadClass(name);
|
||||
|
||||
if (c == null)
|
||||
throw ex;
|
||||
|
||||
if (resolve)
|
||||
resolveClass(c);
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("loaded " + c+ " from "+c.getClassLoader());
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Enumeration<URL> getResources(String name) throws IOException
|
||||
{
|
||||
Enumeration<URL> osgiUrls = _osgiBundleClassLoader.getResources(name);
|
||||
Enumeration<URL> urls = super.getResources(name);
|
||||
if (_lookInOsgiFirst)
|
||||
{
|
||||
return Collections.enumeration(toList(osgiUrls, urls));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Collections.enumeration(toList(urls, osgiUrls));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
try
|
||||
{
|
||||
return _lookInOsgiFirst ? _osgiBundleClassLoader.loadClass(name) : super.findClass(name);
|
||||
}
|
||||
catch (ClassNotFoundException cne)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _lookInOsgiFirst ? super.findClass(name) : _osgiBundleClassLoader.loadClass(name);
|
||||
}
|
||||
catch (ClassNotFoundException cne2)
|
||||
{
|
||||
throw cne;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param e
|
||||
* @param e2
|
||||
* @return
|
||||
*/
|
||||
private List<URL> toList(Enumeration<URL> e, Enumeration<URL> e2)
|
||||
{
|
||||
List<URL> list = new ArrayList<URL>();
|
||||
while (e != null && e.hasMoreElements())
|
||||
list.add(e.nextElement());
|
||||
while (e2 != null && e2.hasMoreElements())
|
||||
list.add(e2.nextElement());
|
||||
return list;
|
||||
}
|
||||
}
|
|
@ -14,7 +14,8 @@ package org.eclipse.jetty.osgi.boot.utils;
|
|||
|
||||
import java.net.URL;
|
||||
|
||||
import org.eclipse.jetty.osgi.boot.OSGiAppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
|
||||
|
||||
/**
|
||||
* Fix various shortcomings with the way jasper parses the tld files.
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -144,7 +144,6 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
{
|
||||
// observed this on felix-2.0.0
|
||||
String location = bundle.getLocation();
|
||||
// System.err.println("location " + location);
|
||||
if (location.startsWith("file:/"))
|
||||
{
|
||||
URI uri = new URI(URIUtil.encodePath(location));
|
||||
|
@ -292,7 +291,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 +327,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()))
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>7.6.4-SNAPSHOT</version>
|
||||
<version>7.6.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
<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-context</module>
|
||||
<module>test-jetty-osgi</module>
|
||||
</modules>
|
||||
<build>
|
||||
|
@ -72,6 +74,11 @@
|
|||
</build>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
<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.6-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>test-jetty-osgi-context</artifactId>
|
||||
<name>Jetty :: OSGi :: Context</name>
|
||||
<description>Test Jetty OSGi bundle with a ContextHandler</description>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.testcontext</bundle-symbolic-name>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</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>
|
||||
<resource>
|
||||
<directory>src/main/context</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.testcontext;singleton:=true</Bundle-SymbolicName>
|
||||
<Bundle-Name>Jetty OSGi Test Context</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>
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
|
||||
|
||||
<!-- Get root for static content, could be on file system or this bundle -->
|
||||
<Call id="res" class="org.eclipse.jetty.util.resource.Resource" name="newResource">
|
||||
<Arg><Property name="bundle.root"/></Arg>
|
||||
</Call>
|
||||
|
||||
<Ref id="res">
|
||||
<Call id="base" name="addPath">
|
||||
<Arg>/static/</Arg>
|
||||
</Call>
|
||||
</Ref>
|
||||
|
||||
<Set name="contextPath">/unset</Set>
|
||||
|
||||
<!-- Set up the base resource for static files relative to inside bundle -->
|
||||
<Set name="baseResource">
|
||||
<Ref id="base"/>
|
||||
</Set>
|
||||
|
||||
<Set name="handler">
|
||||
<New class="org.eclipse.jetty.server.handler.ResourceHandler">
|
||||
<Set name="welcomeFiles">
|
||||
<Array type="String">
|
||||
<Item>index.html</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
<Set name="cacheControl">max-age=3600,public</Set>
|
||||
</New>
|
||||
</Set>
|
||||
|
||||
</Configure>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
// ========================================================================
|
||||
// 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.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 ContextHandler
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class Activator implements BundleActivator
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
public void start(BundleContext context) throws Exception
|
||||
{
|
||||
ContextHandler ch = new ContextHandler();
|
||||
Dictionary props = new Hashtable();
|
||||
props.put("contextPath","/acme");
|
||||
props.put("Jetty-ContextFilePath", "acme.xml");
|
||||
context.registerService(ContextHandler.class.getName(),ch,props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the activator.
|
||||
*
|
||||
* @see
|
||||
* org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
|
||||
*/
|
||||
public void stop(BundleContext context) throws Exception
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
<html>
|
||||
<body>
|
||||
<h1>Test OSGi Context</h1>
|
||||
<p>ContextHandler registered as a service successfully deployed.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -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.6-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>
|
|
@ -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
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
<html>
|
||||
<body>
|
||||
<h1>Test OSGi WebApp</h1>
|
||||
<p>Webapp registered by bundle as service successfully deployed.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -134,6 +134,24 @@
|
|||
<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>
|
||||
|
||||
<!-- test osgi contexthandler service -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>test-jetty-osgi-context</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ops4j.pax.exam</groupId>
|
||||
<artifactId>pax-exam</artifactId>
|
||||
|
@ -157,6 +175,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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,177 @@
|
|||
// ========================================================================
|
||||
// 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.server.handler.ContextHandler;
|
||||
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;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
/**
|
||||
* TestJettyOSGiBootContextAsService
|
||||
*
|
||||
* Tests deployment of a ContextHandler as an osgi Service.
|
||||
*
|
||||
* Tests the ServiceContextProvider.
|
||||
*
|
||||
*/
|
||||
@RunWith( JUnit4TestRunner.class )
|
||||
public class JettyOSGiBootContextAsService
|
||||
{
|
||||
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-context" ).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.testcontext");
|
||||
Assert.assertNotNull("Could not find the org.eclipse.jetty.test-jetty-osgi-context.jar bundle", testWebBundle);
|
||||
Assert.assertTrue("The bundle org.eclipse.jetty.testcontext is not correctly resolved", testWebBundle.getState() == Bundle.ACTIVE);
|
||||
|
||||
//now test the context
|
||||
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 Context</h1>") != -1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
ServiceReference[] refs = bundleContext.getServiceReferences(ContextHandler.class.getName(), null);
|
||||
Assert.assertNotNull(refs);
|
||||
Assert.assertEquals(1,refs.length);
|
||||
ContextHandler ch = (ContextHandler)bundleContext.getService(refs[0]);
|
||||
Assert.assertEquals("/acme", ch.getContextPath());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -16,6 +16,7 @@ package org.eclipse.jetty.osgi.boot;
|
|||
|
||||
import static org.ops4j.pax.exam.CoreOptions.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -36,6 +37,8 @@ import org.eclipse.jetty.client.HttpExchange;
|
|||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.osgi.boot.internal.serverfactory.DefaultJettyAtJettyHomeHelper;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.ops4j.pax.exam.Inject;
|
||||
|
@ -50,6 +53,13 @@ import org.osgi.service.http.HttpService;
|
|||
|
||||
|
||||
/**
|
||||
* TestJettyOSGiBootCore
|
||||
*
|
||||
* Tests deploying a bundle (org.eclipse.jetty.osgi.httpservice) that contains a context xml file
|
||||
* that starts up the equinox http servlet.
|
||||
*
|
||||
* This tests the BundleContextProvider.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
@ -65,10 +75,17 @@ public class TestJettyOSGiBootCore
|
|||
*/
|
||||
public static List<Option> provisionCoreJetty()
|
||||
{
|
||||
File base = MavenTestingUtils.getBasedir();
|
||||
File src = new File (base, "src");
|
||||
File tst = new File (src, "test");
|
||||
File config = new File (tst, "config");
|
||||
|
||||
return Arrays.asList(options(
|
||||
// get the jetty home config from the osgi boot bundle.
|
||||
PaxRunnerOptions.vmOptions("-Djetty.port=9876 -D" + DefaultJettyAtJettyHomeHelper.SYS_PROP_JETTY_HOME_BUNDLE + "=org.eclipse.jetty.osgi.boot"),
|
||||
// PaxRunnerOptions.vmOptions("-Djetty.port=9876 -D" + DefaultJettyAtJettyHomeHelper.SYS_PROP_JETTY_HOME_BUNDLE + "=org.eclipse.jetty.osgi.boot"),
|
||||
|
||||
|
||||
PaxRunnerOptions.vmOptions("-Djetty.port=9876 -Djetty.home=" + config.getAbsolutePath()),
|
||||
// CoreOptions.equinox(),
|
||||
|
||||
mavenBundle().groupId( "org.eclipse.jetty.orbit" ).artifactId( "javax.servlet" ).versionAsInProject().noStart(),
|
||||
|
@ -132,7 +149,6 @@ public class TestJettyOSGiBootCore
|
|||
for( Bundle b : bundleContext.getBundles() )
|
||||
{
|
||||
bundlesIndexedBySymbolicName.put(b.getSymbolicName(), b);
|
||||
System.err.println("got " + b.getSymbolicName());
|
||||
}
|
||||
Bundle osgiBoot = bundlesIndexedBySymbolicName.get("org.eclipse.jetty.osgi.boot");
|
||||
Assert.assertNotNull("Could not find the org.eclipse.jetty.osgi.boot bundle", osgiBoot);
|
||||
|
@ -190,6 +206,9 @@ public class TestJettyOSGiBootCore
|
|||
{
|
||||
client.stop();
|
||||
}
|
||||
ServiceReference[] refs = bundleContext.getServiceReferences(ContextHandler.class.getName(), null);
|
||||
Assert.assertNotNull(refs);
|
||||
Assert.assertEquals(1,refs.length);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
// ========================================================================
|
||||
// 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.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
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;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
/**
|
||||
* TestJettyOSGiBootWebAppAsService
|
||||
*
|
||||
* Tests deployment of a WebAppContext as an osgi Service.
|
||||
*
|
||||
* Tests the ServiceWebAppProvider.
|
||||
*
|
||||
* 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();
|
||||
}
|
||||
|
||||
ServiceReference[] refs = bundleContext.getServiceReferences(ContextHandler.class.getName(), null);
|
||||
Assert.assertNotNull(refs);
|
||||
Assert.assertEquals(1,refs.length);
|
||||
WebAppContext wac = (WebAppContext)bundleContext.getService(refs[0]);
|
||||
Assert.assertEquals("/acme", wac.getContextPath());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -29,6 +29,11 @@ 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.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -39,8 +44,15 @@ import org.ops4j.pax.exam.junit.Configuration;
|
|||
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
/**
|
||||
* TestJettyOSGiBootWithJsp
|
||||
*
|
||||
*
|
||||
* Tests deploying a war (standard jetty test webapp). Tests the BundleWebAppProvider.
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
@ -57,7 +69,13 @@ 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 +99,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 +128,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>();
|
||||
|
@ -153,7 +171,7 @@ public class TestJettyOSGiBootWithJsp
|
|||
if (responseStatus == HttpStatus.OK_200) {
|
||||
content = getExchange.getResponseContent();
|
||||
}
|
||||
//System.err.println("content: " + content);
|
||||
|
||||
Assert.assertTrue(content.indexOf("<tr><th>ServletPath:</th><td>/jsp/dump.jsp</td></tr>") != -1);
|
||||
}
|
||||
finally
|
||||
|
@ -161,6 +179,11 @@ public class TestJettyOSGiBootWithJsp
|
|||
client.stop();
|
||||
}
|
||||
|
||||
ServiceReference[] refs = bundleContext.getServiceReferences(ContextHandler.class.getName(), null);
|
||||
Assert.assertNotNull(refs);
|
||||
Assert.assertEquals(1,refs.length);
|
||||
|
||||
//TODO check that the events got sent
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -378,7 +378,6 @@ public abstract class AbstractHttpConnection extends AbstractConnection
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
_writer.setCharacterEncoding(encoding);
|
||||
return _printWriter;
|
||||
|
@ -402,6 +401,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection
|
|||
_responseFields.clear();
|
||||
_response.recycle();
|
||||
_uri.clear();
|
||||
_writer=null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -85,7 +85,6 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
|
||||
protected String _insertSession;
|
||||
protected String _deleteSession;
|
||||
protected String _selectSession;
|
||||
protected String _updateSession;
|
||||
protected String _updateSessionNode;
|
||||
protected String _updateSessionAccessTime;
|
||||
|
@ -110,6 +109,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
String _dbName;
|
||||
boolean _isLower;
|
||||
boolean _isUpper;
|
||||
|
||||
|
||||
|
||||
public DatabaseAdaptor (DatabaseMetaData dbMeta)
|
||||
|
@ -189,6 +189,39 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
|
||||
return "rowId";
|
||||
}
|
||||
|
||||
|
||||
public boolean isEmptyStringNull ()
|
||||
{
|
||||
return (_dbName.startsWith("oracle"));
|
||||
}
|
||||
|
||||
public PreparedStatement getLoadStatement (Connection connection, String rowId, String contextPath, String virtualHosts)
|
||||
throws SQLException
|
||||
{
|
||||
if (contextPath == null || "".equals(contextPath))
|
||||
{
|
||||
if (isEmptyStringNull())
|
||||
{
|
||||
PreparedStatement statement = connection.prepareStatement("select * from "+_sessionTable+
|
||||
" where sessionId = ? and contextPath is null and virtualHost = ?");
|
||||
statement.setString(1, rowId);
|
||||
statement.setString(2, virtualHosts);
|
||||
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
PreparedStatement statement = connection.prepareStatement("select * from "+_sessionTable+
|
||||
" where sessionId = ? and contextPath = ? and virtualHost = ?");
|
||||
statement.setString(1, rowId);
|
||||
statement.setString(2, contextPath);
|
||||
statement.setString(3, virtualHosts);
|
||||
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -628,10 +661,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
|
||||
_deleteSession = "delete from "+_sessionTable+
|
||||
" where "+_sessionTableRowId+" = ?";
|
||||
|
||||
_selectSession = "select * from "+_sessionTable+
|
||||
" where sessionId = ? and contextPath = ? and virtualHost = ?";
|
||||
|
||||
|
||||
_updateSession = "update "+_sessionTable+
|
||||
" set lastNode = ?, accessTime = ?, lastAccessTime = ?, lastSavedTime = ?, expiryTime = ?, map = ? where "+_sessionTableRowId+" = ?";
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.sql.Connection;
|
|||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
@ -831,10 +832,7 @@ public class JDBCSessionManager extends AbstractSessionManager
|
|||
try
|
||||
{
|
||||
connection = getConnection();
|
||||
statement = connection.prepareStatement(_jdbcSessionIdMgr._selectSession);
|
||||
statement.setString(1, id);
|
||||
statement.setString(2, canonicalContextPath);
|
||||
statement.setString(3, vhost);
|
||||
statement = _jdbcSessionIdMgr._dbAdaptor.getLoadStatement(connection, id, canonicalContextPath, vhost);
|
||||
ResultSet result = statement.executeQuery();
|
||||
if (result.next())
|
||||
{
|
||||
|
|
|
@ -79,6 +79,15 @@ public class IncludableGzipFilter extends GzipFilter
|
|||
{
|
||||
return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setHeader(String name, String value)
|
||||
{
|
||||
super.setHeader(name, value);
|
||||
HttpServletResponse response = (HttpServletResponse)getResponse();
|
||||
if (!response.containsHeader(name))
|
||||
response.setHeader("org.eclipse.jetty.server.include." + name, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -97,6 +106,15 @@ public class IncludableGzipFilter extends GzipFilter
|
|||
{
|
||||
return new DeflaterOutputStream(_response.getOutputStream(),new Deflater(_deflateCompressionLevel, _deflateNoWrap));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setHeader(String name, String value)
|
||||
{
|
||||
super.setHeader(name, value);
|
||||
HttpServletResponse response = (HttpServletResponse)getResponse();
|
||||
if (!response.containsHeader(name))
|
||||
response.setHeader("org.eclipse.jetty.server.include." + name, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -108,8 +126,8 @@ public class IncludableGzipFilter extends GzipFilter
|
|||
configureWrappedResponse(wrappedResponse);
|
||||
return wrappedResponse;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Extend CompressedResponseWrapper to be able to set headers during include and to create unchecked printwriters
|
||||
private abstract class IncludableResponseWrapper extends CompressedResponseWrapper
|
||||
{
|
||||
|
@ -124,7 +142,7 @@ public class IncludableGzipFilter extends GzipFilter
|
|||
super.setHeader(name,value);
|
||||
HttpServletResponse response = (HttpServletResponse)getResponse();
|
||||
if (!response.containsHeader(name))
|
||||
response.setHeader("org.eclipse.jetty.server.include."+name,value);;
|
||||
response.setHeader("org.eclipse.jetty.server.include."+name,value);
|
||||
}
|
||||
@Override
|
||||
protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
|
||||
|
|
Loading…
Reference in New Issue