Jetty 12.0.x osgi (#9068)
This commit is contained in:
parent
964e44527d
commit
1abaeb6cee
|
@ -192,6 +192,7 @@ public class MimeTypes
|
|||
.withAll(() ->
|
||||
{
|
||||
Map<String, Type> result = new HashMap<>();
|
||||
|
||||
for (Type type : Type.values())
|
||||
{
|
||||
String key1 = type.toString();
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
<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</groupId>
|
||||
<artifactId>jetty-core</artifactId>
|
||||
<version>12.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi</artifactId>
|
||||
<name>Jetty Core :: OSGi</name>
|
||||
<description>Support for OSGi integration</description>
|
||||
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.osgi</bundle-symbolic-name>
|
||||
<spotbugs.onlyAnalyze>org.eclipse.jetty.osgi.*</spotbugs.onlyAnalyze>
|
||||
<osgi-version>3.18.100</osgi-version>
|
||||
<osgi-services-version>3.11.0</osgi-services-version>
|
||||
<osgi-service-cm-version>1.6.1</osgi-service-cm-version>
|
||||
<osgi-service-component-version>1.5.0</osgi-service-component-version>
|
||||
<osgi-service-event-version>1.4.1</osgi-service-event-version>
|
||||
<osgi-util-version>3.7.100</osgi-util-version>
|
||||
<osgi-util-function-version>1.2.0</osgi-util-function-version>
|
||||
<osgi-util-promise-version>1.2.0</osgi-util-promise-version>
|
||||
<osgi-util-measurement-version>1.0.2</osgi-util-measurement-version>
|
||||
<osgi-util-position-version>1.0.1</osgi-util-position-version>
|
||||
<osgi-util-tracker-version>1.5.4</osgi-util-tracker-version>
|
||||
<osgi-util-xml-version>1.0.2</osgi-util-xml-version>
|
||||
<equinox-http-servlet-version>1.0.0-v20070606</equinox-http-servlet-version>
|
||||
<jacoco.skip>true</jacoco.skip>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>
|
||||
@{argLine} ${jetty.surefire.argLine} --add-reads org.eclipse.jetty.server=org.eclipse.jetty.logging --add-opens org.eclipse.jetty.server/org.eclipse.jetty.server=ALL-UNNAMED
|
||||
</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-Activator>org.eclipse.jetty.osgi.JettyBootstrapActivator</Bundle-Activator>
|
||||
<DynamicImport-Package>org.eclipse.jetty.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))"</DynamicImport-Package>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
<version>${osgi-services-version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<!-- we use the servlet jar from orbit -->
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<!-- cannot override core java classes with Java 9+ -->
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>org.osgi.foundation</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
<version>${osgi-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.service.cm</artifactId>
|
||||
<version>${osgi-service-cm-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.service.component</artifactId>
|
||||
<version>${osgi-service-component-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.service.event</artifactId>
|
||||
<version>${osgi-service-event-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.util.tracker</artifactId>
|
||||
<version>${osgi-util-tracker-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.equinox.http</groupId>
|
||||
<artifactId>servlet</artifactId>
|
||||
<version>${equinox-http-servlet-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-ee</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.service.cm</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.service.event</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.util.tracker</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-slf4j-impl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,286 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.osgi;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.ee.Deployable;
|
||||
import org.eclipse.jetty.osgi.util.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.osgi.util.OSGiClassLoader;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Environment;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* AbstractContextProvider
|
||||
*
|
||||
* Base class for DeploymentManager Providers that can deploy ContextHandlers into
|
||||
* Jetty that have been discovered via OSGI either as bundles or services.
|
||||
*/
|
||||
public abstract class AbstractContextProvider extends AbstractLifeCycle implements AppProvider
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractContextProvider.class);
|
||||
|
||||
private DeploymentManager _deploymentManager;
|
||||
private Server _server;
|
||||
private ContextFactory _contextFactory;
|
||||
private String _environment;
|
||||
private final Map<String, String> _properties = new HashMap<>();
|
||||
|
||||
public AbstractContextProvider(String environment, Server server, ContextFactory contextFactory)
|
||||
{
|
||||
_environment = Objects.requireNonNull(environment);
|
||||
_server = Objects.requireNonNull(server);
|
||||
_contextFactory = Objects.requireNonNull(contextFactory);
|
||||
}
|
||||
|
||||
public Server getServer()
|
||||
{
|
||||
return _server;
|
||||
}
|
||||
|
||||
public Map<String, String> getProperties()
|
||||
{
|
||||
return _properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextHandler createContextHandler(App app) throws Exception
|
||||
{
|
||||
if (app == null)
|
||||
return null;
|
||||
|
||||
//Create a ContextHandler suitable to deploy in OSGi
|
||||
ContextHandler h = _contextFactory.createContextHandler(this, app);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeploymentManager(DeploymentManager deploymentManager)
|
||||
{
|
||||
_deploymentManager = deploymentManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnvironmentName()
|
||||
{
|
||||
return _environment;
|
||||
}
|
||||
|
||||
public DeploymentManager getDeploymentManager()
|
||||
{
|
||||
return _deploymentManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extractWars.
|
||||
* This is equivalent to getting the {@link Deployable#EXTRACT_WARS} property.
|
||||
*
|
||||
* @return the extractWars
|
||||
*/
|
||||
public boolean isExtractWars()
|
||||
{
|
||||
return Boolean.parseBoolean(_properties.get(Deployable.EXTRACT_WARS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the extractWars.
|
||||
* This is equivalent to setting the {@link Deployable#EXTRACT_WARS} property.
|
||||
*
|
||||
* @param extractWars the extractWars to set
|
||||
*/
|
||||
public void setExtractWars(boolean extractWars)
|
||||
{
|
||||
_properties.put(Deployable.EXTRACT_WARS, Boolean.toString(extractWars));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parentLoaderPriority.
|
||||
* This is equivalent to getting the {@link Deployable#PARENT_LOADER_PRIORITY} property.
|
||||
*
|
||||
* @return the parentLoaderPriority
|
||||
*/
|
||||
public boolean isParentLoaderPriority()
|
||||
{
|
||||
return Boolean.parseBoolean(_properties.get(Deployable.PARENT_LOADER_PRIORITY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parentLoaderPriority.
|
||||
* This is equivalent to setting the {@link Deployable#PARENT_LOADER_PRIORITY} property.
|
||||
*
|
||||
* @param parentLoaderPriority the parentLoaderPriority to set
|
||||
*/
|
||||
public void setParentLoaderPriority(boolean parentLoaderPriority)
|
||||
{
|
||||
_properties.put(Deployable.PARENT_LOADER_PRIORITY, Boolean.toString(parentLoaderPriority));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the defaultsDescriptor.
|
||||
* This is equivalent to getting the {@link Deployable#DEFAULTS_DESCRIPTOR} property.
|
||||
*
|
||||
* @return the defaultsDescriptor
|
||||
*/
|
||||
public String getDefaultsDescriptor()
|
||||
{
|
||||
return _properties.get(Deployable.DEFAULTS_DESCRIPTOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the defaultsDescriptor.
|
||||
* This is equivalent to setting the {@link Deployable#DEFAULTS_DESCRIPTOR} property.
|
||||
*
|
||||
* @param defaultsDescriptor the defaultsDescriptor to set
|
||||
*/
|
||||
public void setDefaultsDescriptor(String defaultsDescriptor)
|
||||
{
|
||||
_properties.put(Deployable.DEFAULTS_DESCRIPTOR, defaultsDescriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is equivalent to setting the {@link Deployable#CONFIGURATION_CLASSES} property.
|
||||
* @param configurations The configuration class names as a comma separated list
|
||||
*/
|
||||
public void setConfigurationClasses(String configurations)
|
||||
{
|
||||
setConfigurationClasses(StringUtil.isBlank(configurations) ? null : configurations.split(","));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is equivalent to setting the {@link Deployable#CONFIGURATION_CLASSES} property.
|
||||
* @param configurations The configuration class names.
|
||||
*/
|
||||
public void setConfigurationClasses(String[] configurations)
|
||||
{
|
||||
_properties.put(Deployable.CONFIGURATION_CLASSES, (configurations == null)
|
||||
? null
|
||||
: String.join(",", configurations));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* This is equivalent to getting the {@link Deployable#CONFIGURATION_CLASSES} property.
|
||||
* @return The configuration class names.
|
||||
*/
|
||||
public String[] getConfigurationClasses()
|
||||
{
|
||||
String cc = _properties.get(Deployable.CONFIGURATION_CLASSES);
|
||||
return cc == null ? new String[0] : cc.split(",");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the temporary directory for deployment.
|
||||
* <p>
|
||||
* This is equivalent to setting the {@link Deployable#BASE_TEMP_DIR} property.
|
||||
* If not set, then the <code>java.io.tmpdir</code> System Property is used.
|
||||
*
|
||||
* @param directory the new work directory
|
||||
*/
|
||||
public void setTempDir(String directory)
|
||||
{
|
||||
_properties.put(Deployable.BASE_TEMP_DIR, directory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the temporary directory for deployment.
|
||||
* <p>
|
||||
* This is equivalent to setting the {@link Deployable#BASE_TEMP_DIR} property.
|
||||
* If not set, then the <code>java.io.tmpdir</code> System Property is used.
|
||||
*
|
||||
* @param directory the new work directory
|
||||
*/
|
||||
public void setTempDir(File directory)
|
||||
{
|
||||
_properties.put(Deployable.BASE_TEMP_DIR, directory.getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the temporary directory for deployment.
|
||||
* <p>
|
||||
* This is equivalent to getting the {@link Deployable#BASE_TEMP_DIR} property.
|
||||
*
|
||||
* @return the user supplied work directory (null if user has not set Temp Directory yet)
|
||||
*/
|
||||
public File getTempDir()
|
||||
{
|
||||
String tmpDir = _properties.get(Deployable.BASE_TEMP_DIR);
|
||||
return tmpDir == null ? null : new File(tmpDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tldBundles Comma separated list of bundles that contain tld jars
|
||||
* that should be setup on the context instances created here.
|
||||
*/
|
||||
public void setTldBundles(String tldBundles)
|
||||
{
|
||||
_properties.put(OSGiWebappConstants.REQUIRE_TLD_BUNDLE, tldBundles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The list of bundles that contain tld jars that should be setup on
|
||||
* the contexts create here.
|
||||
*/
|
||||
public String getTldBundles()
|
||||
{
|
||||
return _properties.get(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
|
||||
}
|
||||
|
||||
public boolean isDeployable(Bundle bundle)
|
||||
{
|
||||
if (bundle == null)
|
||||
return false;
|
||||
|
||||
//check environment matches
|
||||
if (getEnvironmentName().equalsIgnoreCase(bundle.getHeaders().get(OSGiWebappConstants.JETTY_ENVIRONMENT)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isDeployable(ServiceReference service)
|
||||
{
|
||||
if (service == null)
|
||||
return false;
|
||||
|
||||
//has it been deployed before?
|
||||
if (!StringUtil.isBlank((String)service.getProperty(OSGiWebappConstants.WATERMARK)))
|
||||
return false;
|
||||
|
||||
//destined for our environment?
|
||||
if (getEnvironmentName().equalsIgnoreCase((String)service.getProperty(OSGiWebappConstants.JETTY_ENVIRONMENT)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -11,8 +11,11 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
package org.eclipse.jetty.osgi;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
|
@ -21,7 +24,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.osgi.util.Util;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
@ -41,22 +45,31 @@ public class BundleContextProvider extends AbstractContextProvider implements Bu
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractContextProvider.class);
|
||||
|
||||
private Map<String, App> _appMap = new HashMap<String, App>();
|
||||
private Map<Path, App> _appMap = new HashMap<>();
|
||||
|
||||
private Map<Bundle, List<App>> _bundleMap = new HashMap<Bundle, List<App>>();
|
||||
private Map<Bundle, List<App>> _bundleMap = new HashMap<>();
|
||||
|
||||
private ServiceRegistration _serviceRegForBundles;
|
||||
|
||||
private BundleTracker _tracker;
|
||||
|
||||
/**
|
||||
* ContextBundleTracker
|
||||
*
|
||||
* Track deployment of Bundles that should be deployed to Jetty as contexts.
|
||||
*/
|
||||
public class ContextBundleTracker extends BundleTracker
|
||||
{
|
||||
protected String _managedServerName;
|
||||
protected String _serverName;
|
||||
|
||||
public ContextBundleTracker(BundleContext bundleContext, String managedServerName)
|
||||
/**
|
||||
* @param bundleContext our bundle
|
||||
* @param serverName the Server instance to which we will deploy contexts
|
||||
*/
|
||||
public ContextBundleTracker(BundleContext bundleContext, String serverName)
|
||||
{
|
||||
super(bundleContext, Bundle.ACTIVE | Bundle.STOPPING, null);
|
||||
_managedServerName = managedServerName;
|
||||
_serverName = serverName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -65,8 +78,8 @@ public class BundleContextProvider extends AbstractContextProvider implements Bu
|
|||
try
|
||||
{
|
||||
String serverName = (String)bundle.getHeaders().get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
if ((StringUtil.isBlank(serverName) && _managedServerName.equals(OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME)) ||
|
||||
(!StringUtil.isBlank(serverName) && (serverName.equals(_managedServerName))))
|
||||
if ((StringUtil.isBlank(serverName) && _serverName.equals(OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME)) ||
|
||||
(!StringUtil.isBlank(serverName) && (serverName.equals(_serverName))))
|
||||
{
|
||||
if (bundleAdded(bundle))
|
||||
return bundle;
|
||||
|
@ -93,21 +106,23 @@ public class BundleContextProvider extends AbstractContextProvider implements Bu
|
|||
}
|
||||
}
|
||||
|
||||
public BundleContextProvider(ServerInstanceWrapper wrapper)
|
||||
public BundleContextProvider(String environment, Server server, ContextFactory contextFactory)
|
||||
{
|
||||
super(wrapper);
|
||||
super(environment, server, contextFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
String serverName = (String)getServer().getAttribute(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
|
||||
//Track bundles that are ContextHandlers that should be deployed
|
||||
_tracker = new ContextBundleTracker(FrameworkUtil.getBundle(this.getClass()).getBundleContext(), getServerInstanceWrapper().getManagedServerName());
|
||||
_tracker = new ContextBundleTracker(FrameworkUtil.getBundle(this.getClass()).getBundleContext(), serverName);
|
||||
_tracker.open();
|
||||
|
||||
//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());
|
||||
properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, serverName);
|
||||
_serviceRegForBundles = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(BundleProvider.class.getName(), this, properties);
|
||||
super.doStart();
|
||||
}
|
||||
|
@ -131,35 +146,49 @@ public class BundleContextProvider extends AbstractContextProvider implements Bu
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy a bundle as a Jetty context.
|
||||
*/
|
||||
@Override
|
||||
public boolean bundleAdded(Bundle bundle) throws Exception
|
||||
{
|
||||
if (bundle == null)
|
||||
return false;
|
||||
|
||||
if (!isDeployable(bundle))
|
||||
return false;
|
||||
|
||||
//If the bundle defines a Web-ContextPath then its probably a webapp and the BundleWebAppProvider should deploy it
|
||||
if ((String)bundle.getHeaders().get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH) != null)
|
||||
if (bundle.getHeaders().get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH) != null)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("BundleContextProvider ignoring bundle {} with {} set", bundle.getSymbolicName(), OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
|
||||
return false;
|
||||
}
|
||||
|
||||
String contextFiles = (String)bundle.getHeaders().get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH);
|
||||
//comma separated list of context xml files, each of which is a separate ContextHandler to deploy
|
||||
String contextFiles = bundle.getHeaders().get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH);
|
||||
|
||||
//no contexts to deploy, ignore it
|
||||
if (contextFiles == null)
|
||||
return false;
|
||||
|
||||
//is the bundle destined for my environment?
|
||||
String jettyHome = (String)getServer().getAttribute(OSGiServerConstants.JETTY_HOME);
|
||||
Path jettyHomePath = (StringUtil.isBlank(jettyHome) ? null : Paths.get(jettyHome));
|
||||
|
||||
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);
|
||||
OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle);
|
||||
URI contextFilePath = Util.resolvePathAsLocalizedURI(contextFile, app.getBundle(), jettyHomePath);
|
||||
|
||||
//set up the single context file for this deployment
|
||||
app.getProperties().put(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH, contextFilePath.toString());
|
||||
|
||||
_appMap.put(app.getPath(), app);
|
||||
List<App> apps = _bundleMap.get(bundle);
|
||||
if (apps == null)
|
||||
{
|
||||
|
@ -189,11 +218,13 @@ public class BundleContextProvider extends AbstractContextProvider implements Bu
|
|||
{
|
||||
for (App app : apps)
|
||||
{
|
||||
_appMap.remove(app.getOriginId());
|
||||
if (_appMap.remove(app.getPath()) != null)
|
||||
{
|
||||
getDeploymentManager().removeApp(app);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return removed; //true if even 1 context was removed associated with this bundle
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot;
|
||||
package org.eclipse.jetty.osgi;
|
||||
|
||||
import org.osgi.framework.Bundle;
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot;
|
||||
package org.eclipse.jetty.osgi;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
|
@ -19,8 +19,8 @@ import java.util.Hashtable;
|
|||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.ee9.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.ee9.osgi.boot.utils.Util;
|
||||
import org.eclipse.jetty.osgi.util.Util;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
@ -36,9 +36,9 @@ import org.slf4j.LoggerFactory;
|
|||
* <p>
|
||||
* A Jetty Provider that knows how to deploy a WebApp contained inside a Bundle.
|
||||
*/
|
||||
public class BundleWebAppProvider extends AbstractWebAppProvider implements BundleProvider
|
||||
public class BundleWebAppProvider extends AbstractContextProvider implements BundleProvider
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractWebAppProvider.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractContextProvider.class);
|
||||
|
||||
/**
|
||||
* Map of Bundle to App. Used when a Bundle contains a webapp.
|
||||
|
@ -65,6 +65,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund
|
|||
try
|
||||
{
|
||||
String serverName = (String)bundle.getHeaders().get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
|
||||
if ((StringUtil.isBlank(serverName) && _managedServerName.equals(OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME)) ||
|
||||
(!StringUtil.isBlank(serverName) && (serverName.equals(_managedServerName))))
|
||||
{
|
||||
|
@ -93,19 +94,20 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund
|
|||
}
|
||||
}
|
||||
|
||||
public BundleWebAppProvider(ServerInstanceWrapper wrapper)
|
||||
public BundleWebAppProvider(String environment, Server server, ContextFactory contextFactory)
|
||||
{
|
||||
super(wrapper);
|
||||
super(environment, server, contextFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
_webappTracker = new WebAppTracker(FrameworkUtil.getBundle(this.getClass()).getBundleContext(), getServerInstanceWrapper().getManagedServerName());
|
||||
String serverName = (String)getServer().getAttribute(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
_webappTracker = new WebAppTracker(FrameworkUtil.getBundle(this.getClass()).getBundleContext(), serverName);
|
||||
_webappTracker.open();
|
||||
//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<>();
|
||||
properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, getServerInstanceWrapper().getManagedServerName());
|
||||
properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, serverName);
|
||||
_serviceRegForBundles = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(BundleProvider.class.getName(), this, properties);
|
||||
super.doStart();
|
||||
}
|
||||
|
@ -131,6 +133,29 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund
|
|||
super.doStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeployable(Bundle bundle)
|
||||
{
|
||||
//is it destined for my environment?
|
||||
if (!super.isDeployable(bundle))
|
||||
return false;
|
||||
|
||||
//has a war path, could be a webapp
|
||||
if (!StringUtil.isBlank(Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH, bundle.getHeaders())))
|
||||
return true;
|
||||
|
||||
//has a context path header, could be a webapp
|
||||
if (!StringUtil.isBlank(Util.getManifestHeaderValue(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH, bundle.getHeaders())))
|
||||
return true;
|
||||
|
||||
//has a web.xml, could be a webapp
|
||||
if (bundle.getEntry("/WEB-INF/web.xml") != null)
|
||||
return true;
|
||||
|
||||
//not a webapp
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A bundle has been added that could be a webapp
|
||||
*
|
||||
|
@ -142,28 +167,26 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund
|
|||
if (bundle == null)
|
||||
return false;
|
||||
|
||||
//can this bundle be deployed to my environment?
|
||||
if (!isDeployable(bundle))
|
||||
return false;
|
||||
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(getServerInstanceWrapper().getParentClassLoaderForWebapps());
|
||||
String contextPath = null;
|
||||
Thread.currentThread().setContextClassLoader((ClassLoader)getServer().getAttribute(OSGiServerConstants.SERVER_CLASSLOADER));
|
||||
try
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
Dictionary<String, String> headers = bundle.getHeaders();
|
||||
|
||||
//does the bundle have a OSGiWebappConstants.JETTY_WAR_FOLDER_PATH
|
||||
String resourcePath = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH, headers);
|
||||
if (resourcePath != null)
|
||||
String staticResourcesLocation = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH, headers);
|
||||
if (staticResourcesLocation != null)
|
||||
{
|
||||
String base = resourcePath;
|
||||
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);
|
||||
OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle);
|
||||
app.setPathToResourceBase(staticResourcesLocation);
|
||||
_bundleMap.put(bundle, app);
|
||||
getDeploymentManager().addApp(app);
|
||||
return true;
|
||||
|
@ -173,12 +196,8 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund
|
|||
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);
|
||||
OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle);
|
||||
app.setPathToResourceBase(base);
|
||||
_bundleMap.put(bundle, app);
|
||||
getDeploymentManager().addApp(app);
|
||||
return true;
|
||||
|
@ -189,24 +208,16 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund
|
|||
{
|
||||
//Could be a static webapp with no web.xml
|
||||
String base = ".";
|
||||
contextPath = 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);
|
||||
OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle);
|
||||
app.setPathToResourceBase(base);
|
||||
_bundleMap.put(bundle, app);
|
||||
getDeploymentManager().addApp(app);
|
||||
return true;
|
||||
}
|
||||
|
||||
//not a webapp
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
|
@ -230,28 +241,4 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund
|
|||
}
|
||||
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 = StringUtil.replace(location, '\\', '/').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;
|
||||
}
|
||||
}
|
|
@ -11,19 +11,13 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot;
|
||||
package org.eclipse.jetty.osgi;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
/**
|
||||
* ServiceProvider
|
||||
*
|
||||
* Jetty DeploymentManager Provider api for webapps or ContextHandlers that are discovered as OSGi services.
|
||||
*/
|
||||
public interface ServiceProvider
|
||||
public interface ContextFactory
|
||||
{
|
||||
public boolean serviceAdded(ServiceReference ref, ContextHandler handler) throws Exception;
|
||||
|
||||
public boolean serviceRemoved(ServiceReference ref, ContextHandler handler) throws Exception;
|
||||
ContextHandler createContextHandler(AbstractContextProvider provider, App app) throws Exception;
|
||||
}
|
|
@ -11,11 +11,13 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.internal.serverfactory;
|
||||
package org.eclipse.jetty.osgi;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Dictionary;
|
||||
import java.util.Enumeration;
|
||||
|
@ -24,32 +26,28 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.eclipse.jetty.ee10.osgi.boot.JettyBootstrapActivator;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.OSGiServerConstants;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.OSGiClassLoader;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.Util;
|
||||
import org.eclipse.jetty.osgi.util.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.osgi.util.OSGiClassLoader;
|
||||
import org.eclipse.jetty.osgi.util.Util;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.resource.JarResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* DefaultJettyAtJettyHomeHelper
|
||||
* JettyBootstrapActivator
|
||||
* <p>
|
||||
* Creates a default instance of Jetty, based on the values of the
|
||||
* System properties "jetty.home" or "jetty.home.bundle", one of which
|
||||
* must be specified in order to create the default instance.
|
||||
* <p>
|
||||
* Called by the {@link JettyBootstrapActivator} during the starting of the
|
||||
* bundle.
|
||||
* Bootstrap jetty and publish a default Server instance as an OSGi service.
|
||||
*/
|
||||
public class DefaultJettyAtJettyHomeHelper
|
||||
public class JettyBootstrapActivator implements BundleActivator
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DefaultJettyAtJettyHomeHelper.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JettyBootstrapActivator.class);
|
||||
|
||||
private static JettyBootstrapActivator INSTANCE = null;
|
||||
|
||||
/**
|
||||
* contains a comma separated list of paths to the etc/jetty-*.xml files
|
||||
|
@ -66,10 +64,73 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
*/
|
||||
public static final String DEFAULT_JETTYHOME = "/jettyhome";
|
||||
|
||||
private ServiceRegistration<?> _registeredServer;
|
||||
/* private PackageAdminServiceTracker _packageAdminServiceTracker;*/
|
||||
|
||||
/**
|
||||
* Called by the JettyBootStrapActivator. If the system property jetty.home
|
||||
* is defined and points to a folder, creates a corresponding jetty
|
||||
* server.
|
||||
* Setup a new jetty Server, register it as a service.
|
||||
*
|
||||
* @param context the bundle context
|
||||
*/
|
||||
@Override
|
||||
public void start(final BundleContext context) throws Exception
|
||||
{
|
||||
// track other bundles and fragments attached to this bundle that we
|
||||
// should activate, as OSGi will not call activators for them.
|
||||
/* _packageAdminServiceTracker = new PackageAdminServiceTracker(context);*/
|
||||
|
||||
ServiceReference[] references = context.getAllServiceReferences("org.eclipse.jetty.http.HttpFieldPreEncoder", null);
|
||||
|
||||
if (references == null || references.length == 0)
|
||||
LOG.warn("OSGi support for java.util.ServiceLoader may not be present. You may experience runtime errors.");
|
||||
|
||||
// Create a default jetty instance right now.
|
||||
startJettyAtJettyHome(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the activator.
|
||||
*
|
||||
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
|
||||
*/
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception
|
||||
{
|
||||
|
||||
/* if (_packageAdminServiceTracker != null)
|
||||
{
|
||||
_packageAdminServiceTracker.stop();
|
||||
context.removeServiceListener(_packageAdminServiceTracker);
|
||||
_packageAdminServiceTracker = null;
|
||||
}
|
||||
*/
|
||||
try
|
||||
{
|
||||
if (_registeredServer != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_registeredServer.unregister();
|
||||
}
|
||||
catch (IllegalArgumentException ill)
|
||||
{
|
||||
// already unregistered.
|
||||
}
|
||||
finally
|
||||
{
|
||||
_registeredServer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
INSTANCE = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the system property jetty.home is defined and points to a folder,
|
||||
* creates a corresponding jetty server.
|
||||
* <p>
|
||||
* If the system property jetty.home.bundle is defined and points to a
|
||||
* bundle, look for the configuration of jetty inside that bundle.
|
||||
|
@ -87,10 +148,9 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
* </p>
|
||||
*
|
||||
* @param bundleContext the bundle context
|
||||
* @return the configured server
|
||||
* @throws Exception if unable to create / configure / or start the server
|
||||
*/
|
||||
public static Server startJettyAtJettyHome(BundleContext bundleContext) throws Exception
|
||||
private void startJettyAtJettyHome(BundleContext bundleContext) throws Exception
|
||||
{
|
||||
String jettyHomeSysProp = System.getProperty(OSGiServerConstants.JETTY_HOME);
|
||||
String jettyHomeBundleSysProp = System.getProperty(OSGiServerConstants.JETTY_HOME_BUNDLE);
|
||||
|
@ -112,7 +172,7 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
if (!jettyHomeDir.exists() || !jettyHomeDir.isDirectory())
|
||||
{
|
||||
LOG.warn("Unable to locate the jetty.home folder {}", jettyHomeSysProp);
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
//set jetty.home
|
||||
|
@ -135,14 +195,14 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
if (jettyHomeBundle == null)
|
||||
{
|
||||
LOG.warn("Unable to find the jetty.home.bundle named {}", jettyHomeSysProp);
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (jettyHomeDir == null && jettyHomeBundle == null)
|
||||
{
|
||||
LOG.warn("No default jetty created.");
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
//resolve the jetty xml config files
|
||||
|
@ -196,15 +256,14 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
}
|
||||
}
|
||||
|
||||
//configure the server here rather than letting the JettyServerServiceTracker do it, because we want to be able to
|
||||
//configure the ThreadPool, which can only be done via the constructor, ie from within the xml configuration processing
|
||||
Server server = ServerInstanceWrapper.configure(null, configURLs, properties);
|
||||
//Create the default Server instance
|
||||
Server defaultServer = JettyServerFactory.createServer(OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME, properties, configURLs);
|
||||
|
||||
//Register the default Server instance as an OSGi service.
|
||||
//The JettyServerServiceTracker will notice it and set it up to deploy bundles as wars etc
|
||||
bundleContext.registerService(Server.class.getName(), server, properties);
|
||||
//The JettyServerServiceTrackers will notice it and set it up to deploy bundles as wars etc
|
||||
//for each environment eg ee9,ee10, etc
|
||||
_registeredServer = bundleContext.registerService(Server.class.getName(), defaultServer, properties);
|
||||
LOG.info("Default jetty server configured");
|
||||
return server;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -223,7 +282,7 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
* look for the corresponding jetty configuration files that will be used to
|
||||
* setup the jetty server.
|
||||
*/
|
||||
private static List<URL> getJettyConfigurationURLs(File jettyhome)
|
||||
private List<URL> getJettyConfigurationURLs(File jettyhome)
|
||||
throws MalformedURLException
|
||||
{
|
||||
List<URL> configURLs = new ArrayList<>();
|
||||
|
@ -247,7 +306,7 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
* jetty.etc.config.urls and look for the corresponding jetty configuration
|
||||
* files that will be used to setup the jetty server.
|
||||
*/
|
||||
private static List<URL> getJettyConfigurationURLs(Bundle configurationBundle, Dictionary properties)
|
||||
private List<URL> getJettyConfigurationURLs(Bundle configurationBundle, Dictionary properties)
|
||||
throws Exception
|
||||
{
|
||||
List<URL> configURLs = new ArrayList<>();
|
||||
|
@ -279,9 +338,9 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
//lazily ensure jetty.home value is set based on location of etc files
|
||||
if (properties.get(OSGiServerConstants.JETTY_HOME) == null)
|
||||
{
|
||||
Resource res = findDir(configurationBundle, home);
|
||||
if (res != null)
|
||||
properties.put(OSGiServerConstants.JETTY_HOME, res.toString());
|
||||
Path path = findDir(configurationBundle, home);
|
||||
if (path != null)
|
||||
properties.put(OSGiServerConstants.JETTY_HOME, path.toUri().toString());
|
||||
}
|
||||
|
||||
if (enUrls == null || !enUrls.hasMoreElements())
|
||||
|
@ -295,14 +354,14 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
}
|
||||
|
||||
/**
|
||||
* Get a resource representing a directory inside a bundle. If the dir is null,
|
||||
* return a resource representing the installation location of the bundle.
|
||||
* Resolve a directory inside a bundle. If the dir is null,
|
||||
* return a path representing the installation location of the bundle.
|
||||
*
|
||||
* @param bundle the bundle
|
||||
* @param dir the directory
|
||||
* @return the resource found
|
||||
* @return either the resolved dir inside the bundle, or the path of the bundle itself
|
||||
*/
|
||||
public static Resource findDir(Bundle bundle, String dir)
|
||||
private Path findDir(Bundle bundle, String dir)
|
||||
{
|
||||
if (bundle == null)
|
||||
return null;
|
||||
|
@ -312,18 +371,12 @@ public class DefaultJettyAtJettyHomeHelper
|
|||
File f = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bundle);
|
||||
URL u = f.toURI().toURL();
|
||||
u = BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(u);
|
||||
Resource res = Resource.newResource(u);
|
||||
URI ruri = res.toURI();
|
||||
Path p = Paths.get(u.toURI());
|
||||
|
||||
// check if it is an unarchived bundle
|
||||
if ("file".equalsIgnoreCase(ruri.getScheme()) && FileID.isJavaArchive(ruri))
|
||||
res = JarResource.newJarResource(res);
|
||||
|
||||
//if looking for a directory
|
||||
if (dir != null)
|
||||
res = res.addPath(dir);
|
||||
|
||||
return res;
|
||||
return p.resolve(dir);
|
||||
else
|
||||
return p;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
|
@ -0,0 +1,261 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.osgi;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Dictionary;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.eclipse.jetty.deploy.AppLifeCycle;
|
||||
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.util.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.osgi.util.Util;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* JettyServerFactory
|
||||
*
|
||||
* Configures a jetty Server instance.
|
||||
*/
|
||||
public class JettyServerFactory
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JettyServerFactory.class.getName());
|
||||
|
||||
/**
|
||||
* The value of this property points to the parent director of the jetty.xml
|
||||
* configuration file currently executed. Everything is passed as a URL to
|
||||
* support the case where the bundle is zipped.
|
||||
*/
|
||||
public static final String PROPERTY_THIS_JETTY_XML_FOLDER_URL = "this.jetty.xml.parent.folder.url";
|
||||
|
||||
/*
|
||||
* Create a Server that is suitable for using in OSGi
|
||||
*/
|
||||
public static Server createServer(String name, Dictionary<String, Object> props, List<URL> jettyConfigurations)
|
||||
throws Exception
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
|
||||
Server server = null;
|
||||
ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
|
||||
try
|
||||
{
|
||||
List<URL> sharedURLs = getManagedJettySharedLibFolderUrls(props);
|
||||
|
||||
// Ensure we have a classloader that will have access to all jetty classes
|
||||
ClassLoader libExtClassLoader = LibExtClassLoaderHelper.createLibExtClassLoader(null, sharedURLs, contextCl/*JettyServerFactory.class.getClassLoader()*/);
|
||||
|
||||
ClassLoader serverClassLoader = libExtClassLoader;
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("LibExtClassLoader = {}", libExtClassLoader);
|
||||
|
||||
Thread.currentThread().setContextClassLoader(libExtClassLoader);
|
||||
|
||||
//Get ready to apply jetty configuration files, both those as explicit argument,
|
||||
//as well as those provided by property
|
||||
List<URL> jettyConfigs = new ArrayList<>();
|
||||
if (jettyConfigurations != null)
|
||||
jettyConfigs.addAll(jettyConfigurations);
|
||||
|
||||
//config files provided as part of the osgi properties
|
||||
String jettyConfigFilenames = (String)props.get(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS);
|
||||
if (jettyConfigFilenames != null)
|
||||
{
|
||||
jettyConfigs.addAll(Util.fileNamesAsURLs(jettyConfigFilenames, StringUtil.DEFAULT_DELIMS));
|
||||
}
|
||||
|
||||
Map<String, Object> idMap = new HashMap<>();
|
||||
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
if (props != null)
|
||||
{
|
||||
Enumeration<String> en = props.keys();
|
||||
while (en.hasMoreElements())
|
||||
{
|
||||
String key = en.nextElement();
|
||||
Object value = props.get(key);
|
||||
properties.put(key, value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
try (ResourceFactory.Closeable resourceFactory = ResourceFactory.closeable())
|
||||
{
|
||||
//create the server via config files
|
||||
for (URL jettyConfiguration : jettyConfigurations)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Execute a Jetty configuration file
|
||||
XmlConfiguration config = new XmlConfiguration(resourceFactory.newResource(jettyConfiguration));
|
||||
|
||||
config.getIdMap().putAll(idMap);
|
||||
config.getProperties().putAll(properties);
|
||||
|
||||
// #334062 compute the URL of the folder that contains the
|
||||
// conf file and set it as a property so we can compute relative paths
|
||||
// from it.
|
||||
String urlPath = jettyConfiguration.toString();
|
||||
int lastSlash = urlPath.lastIndexOf('/');
|
||||
if (lastSlash > 4)
|
||||
{
|
||||
urlPath = urlPath.substring(0, lastSlash);
|
||||
config.getProperties().put(PROPERTY_THIS_JETTY_XML_FOLDER_URL, urlPath);
|
||||
}
|
||||
|
||||
Object o = config.configure();
|
||||
server = (Server)o;
|
||||
|
||||
idMap = config.getIdMap();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Configuration error in {}", jettyConfiguration);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if no config files, create the server
|
||||
if (server == null)
|
||||
server = new Server();
|
||||
|
||||
//ensure ContextHandlerCollection
|
||||
ContextHandlerCollection contextHandlerCollection = getContextHandlerCollection(server);
|
||||
if (contextHandlerCollection == null)
|
||||
{
|
||||
contextHandlerCollection = new ContextHandlerCollection();
|
||||
server.setHandler(contextHandlerCollection);
|
||||
}
|
||||
|
||||
//ensure DeploymentManager
|
||||
DeploymentManager deploymentManager = ensureDeploymentManager(server);
|
||||
deploymentManager.setUseStandardBindings(false);
|
||||
List<AppLifeCycle.Binding> deploymentLifeCycleBindings = new ArrayList<>();
|
||||
deploymentLifeCycleBindings.add(new OSGiDeployer(server));
|
||||
deploymentLifeCycleBindings.add(new StandardStarter());
|
||||
deploymentLifeCycleBindings.add(new StandardStopper());
|
||||
deploymentLifeCycleBindings.add(new OSGiUndeployer(server));
|
||||
deploymentManager.setLifeCycleBindings(deploymentLifeCycleBindings);
|
||||
|
||||
server.setAttribute(OSGiServerConstants.JETTY_HOME, properties.get(OSGiServerConstants.JETTY_HOME));
|
||||
server.setAttribute(OSGiServerConstants.JETTY_BASE, properties.get(OSGiServerConstants.JETTY_BASE));
|
||||
server.setAttribute(OSGiServerConstants.SERVER_CLASSLOADER, serverClassLoader);
|
||||
server.setAttribute(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, name);
|
||||
|
||||
return server;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (server != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
LOG.trace("IGNORED", x);
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(contextCl);
|
||||
}
|
||||
}
|
||||
|
||||
private static DeploymentManager ensureDeploymentManager(Server server)
|
||||
{
|
||||
Collection<DeploymentManager> deployers = server.getBeans(DeploymentManager.class);
|
||||
DeploymentManager deploymentManager;
|
||||
|
||||
if (deployers != null)
|
||||
{
|
||||
deploymentManager = deployers.stream().findFirst().get();
|
||||
}
|
||||
else
|
||||
{
|
||||
deploymentManager = new DeploymentManager();
|
||||
deploymentManager.setContexts(getContextHandlerCollection(server));
|
||||
server.addBean(deploymentManager);
|
||||
}
|
||||
|
||||
return deploymentManager;
|
||||
}
|
||||
|
||||
private static ContextHandlerCollection getContextHandlerCollection(Server server)
|
||||
{
|
||||
return (ContextHandlerCollection)server.getDescendant(ContextHandlerCollection.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Jetty Shared Lib Folder URLs in a form that is suitable for
|
||||
* {@link LibExtClassLoaderHelper} to use.
|
||||
*
|
||||
* @param props the properties to look for the configuration in
|
||||
* @return the list of URLs found, or null if none found
|
||||
*/
|
||||
private static List<URL> getManagedJettySharedLibFolderUrls(Dictionary<String, Object> props)
|
||||
{
|
||||
String sharedURLs = (String)props.get(OSGiServerConstants.MANAGED_JETTY_SHARED_LIB_FOLDER_URLS);
|
||||
if (StringUtil.isBlank(sharedURLs))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<URL> libURLs = new ArrayList<>();
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(sharedURLs, StringUtil.DEFAULT_DELIMS, false);
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String tok = tokenizer.nextToken();
|
||||
try
|
||||
{
|
||||
URL url = new URL(tok);
|
||||
url = BundleFileLocatorHelperFactory.getFactory().getHelper().getFileURL(url);
|
||||
if (url.getProtocol().equals("file"))
|
||||
{
|
||||
libURLs.add(new URL("jar:" + url.toExternalForm() + "!/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Unrecognized Jetty Shared Lib URL: {}", url);
|
||||
}
|
||||
}
|
||||
catch (Throwable mfe)
|
||||
{
|
||||
LOG.warn("Unable to process legacy lib folder {}", tok, mfe);
|
||||
}
|
||||
}
|
||||
return libURLs;
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot.internal.webapp;
|
||||
package org.eclipse.jetty.osgi;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
|
@ -25,6 +25,8 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
|
||||
/**
|
||||
* LibExtClassLoaderHelper
|
||||
* <p>
|
||||
|
@ -50,7 +52,6 @@ import java.util.Set;
|
|||
*/
|
||||
public class LibExtClassLoaderHelper
|
||||
{
|
||||
|
||||
/**
|
||||
* IFilesInJettyHomeResourcesProcessor
|
||||
*
|
|
@ -0,0 +1,259 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.osgi;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Dictionary;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.ee.Deployable;
|
||||
import org.eclipse.jetty.osgi.util.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* OSGiApp
|
||||
*
|
||||
* Base class representing info about a WebAppContext/ContextHandler to be deployed into jetty.
|
||||
*/
|
||||
public class OSGiApp extends App
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(OSGiApp.class);
|
||||
|
||||
protected Bundle _bundle;
|
||||
protected ServiceRegistration _registration;
|
||||
protected ContextHandler _contextHandler;
|
||||
protected String _pathToResourceBase;
|
||||
protected String _contextPath;
|
||||
protected Resource _bundleResource;
|
||||
|
||||
/**
|
||||
* Get the install location of a Bundle as a Path
|
||||
* @param bundle the Bundle whose location to return
|
||||
* @return the installed location of the Bundle as a Path
|
||||
* @throws Exception
|
||||
*/
|
||||
private static Path getBundlePath(Bundle bundle) throws Exception
|
||||
{
|
||||
String bundleOverrideLocation = bundle.getHeaders().get(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE);
|
||||
File bundleLocation = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bundle);
|
||||
File root = (bundleOverrideLocation == null ? bundleLocation : new File(bundleOverrideLocation));
|
||||
return Paths.get(root.toURI());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a bundle installed location into a Resource, taking account of
|
||||
* any locations that are actually packed jars, but without a ".jar" extension, eg
|
||||
* as found on equinox. Eg file:///a/b/c/org.eclipse.osgi/89/0/bundleFile
|
||||
* @param bundle the bundle
|
||||
* @return a Resource representing the bundle's installed location
|
||||
* @throws Exception
|
||||
*/
|
||||
private static Resource getBundleAsResource(Bundle bundle) throws Exception
|
||||
{
|
||||
String bundleOverrideLocation = bundle.getHeaders().get(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE);
|
||||
File bundleLocation = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bundle);
|
||||
File root = (bundleOverrideLocation == null ? bundleLocation : new File(bundleOverrideLocation));
|
||||
//Fix some osgiPaths.get( locations which point to an archive, but that doesn't end in .jar
|
||||
URL url = BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(root.toURI().toURL());
|
||||
|
||||
return ResourceFactory.root().newResource(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create a contextPath from bundle headers and information
|
||||
*
|
||||
* @param bundle
|
||||
* @return a contextPath
|
||||
*/
|
||||
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 = StringUtil.replace(location, '\\', '/').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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param manager the DeploymentManager to which to deploy
|
||||
* @param provider the provider that discovered the context/webapp
|
||||
* @param bundle the bundle associated with the context/webapp
|
||||
*/
|
||||
public OSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle)
|
||||
throws Exception
|
||||
{
|
||||
super(manager, provider, getBundlePath(bundle));
|
||||
|
||||
_bundle = Objects.requireNonNull(bundle);
|
||||
_bundleResource = getBundleAsResource(bundle);
|
||||
|
||||
//copy selected bundle headers into the properties
|
||||
Dictionary<String, String> headers = bundle.getHeaders();
|
||||
Enumeration<String> keys = headers.keys();
|
||||
while (keys.hasMoreElements())
|
||||
{
|
||||
String key = keys.nextElement();
|
||||
String val = headers.get(key);
|
||||
if (Deployable.ENVIRONMENT.equalsIgnoreCase(key) || OSGiWebappConstants.JETTY_ENVIRONMENT.equalsIgnoreCase(key))
|
||||
getProperties().put(Deployable.ENVIRONMENT, val);
|
||||
else if (Deployable.DEFAULTS_DESCRIPTOR.equalsIgnoreCase(key) || OSGiWebappConstants.JETTY_DEFAULT_WEB_XML_PATH.equalsIgnoreCase(key))
|
||||
{
|
||||
getProperties().put(Deployable.DEFAULTS_DESCRIPTOR, val);
|
||||
}
|
||||
else if (OSGiWebappConstants.JETTY_WEB_XML_PATH.equalsIgnoreCase(key))
|
||||
{
|
||||
getProperties().put(key, val);
|
||||
}
|
||||
else if (OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH.equalsIgnoreCase(key))
|
||||
{
|
||||
getProperties().put(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
//set up the context path based on the supplied value, or the calculated default
|
||||
setContextPath(getContextPath(bundle));
|
||||
}
|
||||
|
||||
public Resource getBundleResource()
|
||||
{
|
||||
return _bundleResource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextHandler getContextHandler() throws Exception
|
||||
{
|
||||
if (_contextHandler == null)
|
||||
_contextHandler = getAppProvider().createContextHandler(this);
|
||||
return _contextHandler;
|
||||
}
|
||||
|
||||
public void setContextHandler(ContextHandler contextHandler)
|
||||
{
|
||||
_contextHandler = contextHandler;
|
||||
}
|
||||
|
||||
public String getPathToResourceBase()
|
||||
{
|
||||
return _pathToResourceBase;
|
||||
}
|
||||
|
||||
public void setPathToResourceBase(String path)
|
||||
{
|
||||
_pathToResourceBase = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextPath()
|
||||
{
|
||||
return _contextPath;
|
||||
}
|
||||
|
||||
public void setContextPath(String contextPath)
|
||||
{
|
||||
_contextPath = contextPath;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the Jetty deployed context/webapp as a service, as
|
||||
* according to the OSGi Web Application Specification.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -11,13 +11,13 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot;
|
||||
package org.eclipse.jetty.osgi;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.bindings.StandardDeployer;
|
||||
import org.eclipse.jetty.deploy.graph.Node;
|
||||
import org.eclipse.jetty.ee9.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.ee9.osgi.boot.utils.EventSender;
|
||||
import org.eclipse.jetty.osgi.util.EventSender;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
||||
/**
|
||||
* OSGiDeployer
|
||||
|
@ -28,9 +28,9 @@ import org.eclipse.jetty.ee9.osgi.boot.utils.EventSender;
|
|||
public class OSGiDeployer extends StandardDeployer
|
||||
{
|
||||
|
||||
private ServerInstanceWrapper _server;
|
||||
private Server _server;
|
||||
|
||||
public OSGiDeployer(ServerInstanceWrapper server)
|
||||
public OSGiDeployer(Server server)
|
||||
{
|
||||
_server = server;
|
||||
}
|
||||
|
@ -40,22 +40,22 @@ public class OSGiDeployer extends StandardDeployer
|
|||
{
|
||||
//TODO how to NOT send this event if its not a webapp:
|
||||
//OSGi Enterprise Spec only wants an event sent if its a webapp bundle (ie not a ContextHandler)
|
||||
if (!(app instanceof AbstractOSGiApp))
|
||||
if (!(app instanceof OSGiApp))
|
||||
{
|
||||
doProcessBinding(node, app);
|
||||
}
|
||||
else
|
||||
{
|
||||
EventSender.getInstance().send(EventSender.DEPLOYING_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath());
|
||||
EventSender.getInstance().send(EventSender.DEPLOYING_EVENT, ((OSGiApp)app).getBundle(), app.getContextPath());
|
||||
try
|
||||
{
|
||||
doProcessBinding(node, app);
|
||||
((AbstractOSGiApp)app).registerAsOSGiService();
|
||||
EventSender.getInstance().send(EventSender.DEPLOYED_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath());
|
||||
((OSGiApp)app).registerAsOSGiService();
|
||||
EventSender.getInstance().send(EventSender.DEPLOYED_EVENT, ((OSGiApp)app).getBundle(), app.getContextPath());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
EventSender.getInstance().send(EventSender.FAILED_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath());
|
||||
EventSender.getInstance().send(EventSender.FAILED_EVENT, ((OSGiApp)app).getBundle(), app.getContextPath());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,8 @@ public class OSGiDeployer extends StandardDeployer
|
|||
protected void doProcessBinding(Node node, App app) throws Exception
|
||||
{
|
||||
ClassLoader old = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(_server.getParentClassLoaderForWebapps());
|
||||
ClassLoader cl = (ClassLoader)_server.getAttribute(OSGiServerConstants.SERVER_CLASSLOADER);
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
try
|
||||
{
|
||||
super.processBinding(node, app);
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot;
|
||||
package org.eclipse.jetty.osgi;
|
||||
|
||||
/**
|
||||
* OSGiServerConstants
|
||||
|
@ -80,4 +80,15 @@ public class OSGiServerConstants
|
|||
* List of URLs to the folders where the legacy J2EE shared libraries are stored aka lib/ext, lib/jsp etc.
|
||||
*/
|
||||
public static final String MANAGED_JETTY_SHARED_LIB_FOLDER_URLS = "managedJettySharedLibFolderUrls";
|
||||
|
||||
/*
|
||||
* Name of server attribute that stores a classloader suitable as the parent classloader for contexts
|
||||
*/
|
||||
public static final String SERVER_CLASSLOADER = "org.eclipse.jetty.osgi.server.classLoader";
|
||||
|
||||
/**
|
||||
* Name of server attribute that stores a List of Bundles on the server classpath that must be scanned
|
||||
*/
|
||||
public static final String SERVER_CLASSPATH_BUNDLES = "org.eclipse.jetty.osgi.server.classpathBundles";
|
||||
|
||||
}
|
|
@ -11,13 +11,13 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot;
|
||||
package org.eclipse.jetty.osgi;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.bindings.StandardUndeployer;
|
||||
import org.eclipse.jetty.deploy.graph.Node;
|
||||
import org.eclipse.jetty.ee9.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.ee9.osgi.boot.utils.EventSender;
|
||||
import org.eclipse.jetty.osgi.util.EventSender;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
||||
/**
|
||||
* OSGiUndeployer
|
||||
|
@ -27,9 +27,9 @@ import org.eclipse.jetty.ee9.osgi.boot.utils.EventSender;
|
|||
*/
|
||||
public class OSGiUndeployer extends StandardUndeployer
|
||||
{
|
||||
private ServerInstanceWrapper _server;
|
||||
private Server _server;
|
||||
|
||||
public OSGiUndeployer(ServerInstanceWrapper server)
|
||||
public OSGiUndeployer(Server server)
|
||||
{
|
||||
_server = server;
|
||||
}
|
||||
|
@ -37,9 +37,10 @@ public class OSGiUndeployer extends StandardUndeployer
|
|||
@Override
|
||||
public void processBinding(Node node, App app) throws Exception
|
||||
{
|
||||
EventSender.getInstance().send(EventSender.UNDEPLOYING_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath());
|
||||
EventSender.getInstance().send(EventSender.UNDEPLOYING_EVENT, ((OSGiApp)app).getBundle(), app.getContextPath());
|
||||
ClassLoader old = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(_server.getParentClassLoaderForWebapps());
|
||||
ClassLoader cl = (ClassLoader)_server.getAttribute(OSGiServerConstants.SERVER_CLASSLOADER);
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
try
|
||||
{
|
||||
super.processBinding(node, app);
|
||||
|
@ -48,7 +49,7 @@ public class OSGiUndeployer extends StandardUndeployer
|
|||
{
|
||||
Thread.currentThread().setContextClassLoader(old);
|
||||
}
|
||||
EventSender.getInstance().send(EventSender.UNDEPLOYED_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath());
|
||||
((AbstractOSGiApp)app).deregisterAsOSGiService();
|
||||
EventSender.getInstance().send(EventSender.UNDEPLOYED_EVENT, ((OSGiApp)app).getBundle(), app.getContextPath());
|
||||
((OSGiApp)app).deregisterAsOSGiService();
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot;
|
||||
package org.eclipse.jetty.osgi;
|
||||
|
||||
/**
|
||||
* OSGiWebappConstants
|
||||
|
@ -70,7 +70,7 @@ public class OSGiWebappConstants
|
|||
public static final String JETTY_OSGI_BUNDLE = "osgi-bundle";
|
||||
|
||||
/**
|
||||
* List of relative pathes within the bundle to the jetty context files.
|
||||
* List of relative paths within the bundle to the jetty context files.
|
||||
*/
|
||||
public static final String JETTY_CONTEXT_FILE_PATH = "Jetty-ContextFilePath";
|
||||
|
||||
|
@ -119,6 +119,11 @@ public class OSGiWebappConstants
|
|||
*/
|
||||
public static final String JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE = "Jetty-bundleInstall";
|
||||
|
||||
/**
|
||||
* Property naming the environment (eg ee8/ee9/ee10 etc)
|
||||
*/
|
||||
public static final String JETTY_ENVIRONMENT = "Jetty-Environment";
|
||||
|
||||
/**
|
||||
* Comma separated list of bundles that contain tld file used by the webapp.
|
||||
*/
|
|
@ -11,9 +11,8 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot.utils;
|
||||
package org.eclipse.jetty.osgi.util;
|
||||
|
||||
import org.eclipse.jetty.ee9.osgi.boot.utils.internal.DefaultBundleClassLoaderHelper;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
/**
|
||||
|
@ -37,7 +36,7 @@ public interface BundleClassLoaderHelper
|
|||
/**
|
||||
* The name of the custom implementation for this interface in a fragment.
|
||||
*/
|
||||
public static final String CLASS_NAME = "org.eclipse.jetty.ee9.osgi.boot.utils.BundleClassLoaderHelperImpl";
|
||||
public static final String CLASS_NAME = "org.eclipse.jetty.osgi.util.BundleClassLoaderHelperImpl";
|
||||
|
||||
/**
|
||||
* The default instance supports felix and equinox
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot.utils;
|
||||
package org.eclipse.jetty.osgi.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
|
@ -11,13 +11,12 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot.utils;
|
||||
package org.eclipse.jetty.osgi.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import org.eclipse.jetty.ee9.osgi.boot.utils.internal.DefaultFileLocatorHelper;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
/**
|
||||
|
@ -32,7 +31,7 @@ public interface BundleFileLocatorHelper
|
|||
/**
|
||||
* The name of the custom implementation for this interface in a fragment.
|
||||
*/
|
||||
public static final String CLASS_NAME = "org.eclipse.jetty.ee9.osgi.boot.utils.FileLocatorHelperImpl";
|
||||
public static final String CLASS_NAME = "org.eclipse.jetty.osgi.util.FileLocatorHelperImpl";
|
||||
|
||||
/**
|
||||
* The default instance supports felix and equinox
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot.utils;
|
||||
package org.eclipse.jetty.osgi.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
|
@ -11,13 +11,12 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot.utils.internal;
|
||||
package org.eclipse.jetty.osgi.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.ee9.osgi.boot.utils.BundleClassLoaderHelper;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot.utils.internal;
|
||||
package org.eclipse.jetty.osgi.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
|
@ -20,14 +20,13 @@ import java.net.URI;
|
|||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.eclipse.jetty.ee9.osgi.boot.utils.BundleFileLocatorHelper;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.PathResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
/**
|
||||
|
@ -103,7 +102,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
// some osgi frameworks do use the file protocol directly in some
|
||||
// situations. Do use the PathResource to transform the URL into a
|
||||
// File: URL#toURI is broken
|
||||
return new PathResource(url).getFile().getParentFile().getParentFile().getCanonicalFile();
|
||||
return Paths.get(url.toURI()).getParent().getParent().toFile();
|
||||
}
|
||||
else if (url.getProtocol().equals("bundleentry"))
|
||||
{
|
||||
|
@ -112,7 +111,6 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
// the File
|
||||
|
||||
URLConnection con = url.openConnection();
|
||||
con.setUseCaches(Resource.getDefaultUseCaches()); // work around
|
||||
// problems where
|
||||
// url connections
|
||||
// cache
|
||||
|
@ -141,7 +139,6 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
url = bundle.getEntry("/");
|
||||
|
||||
con = url.openConnection();
|
||||
con.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
|
||||
if (BUNDLE_ENTRY_FIELD == null)
|
||||
{
|
||||
|
@ -334,7 +331,6 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
{
|
||||
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
if (BUNDLE_URL_CONNECTION_getLocalURL == null && match(conn.getClass().getName(), BUNDLE_URL_CONNECTION_CLASSES))
|
||||
{
|
||||
BUNDLE_URL_CONNECTION_getLocalURL = conn.getClass().getMethod("getLocalURL");
|
||||
|
@ -369,7 +365,6 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
{
|
||||
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
if (BUNDLE_URL_CONNECTION_getFileURL == null && match(conn.getClass().getName(), BUNDLE_URL_CONNECTION_CLASSES))
|
||||
{
|
||||
BUNDLE_URL_CONNECTION_getFileURL = conn.getClass().getMethod("getFileURL");
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot.utils;
|
||||
package org.eclipse.jetty.osgi.util;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.Hashtable;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot.utils;
|
||||
package org.eclipse.jetty.osgi.util;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot.utils;
|
||||
package org.eclipse.jetty.osgi.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
|
@ -11,18 +11,19 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
package org.eclipse.jetty.osgi.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
/**
|
||||
* BundleProvider
|
||||
*
|
||||
* Jetty DeploymentManager Provider api for webapps or ContextHandlers that are discovered as osgi bundles.
|
||||
*/
|
||||
public interface BundleProvider
|
||||
public interface ServerClasspathContributor
|
||||
{
|
||||
public boolean bundleAdded(Bundle bundle) throws Exception;
|
||||
|
||||
public boolean bundleRemoved(Bundle bundle) throws Exception;
|
||||
/**
|
||||
* Get bundles that should be on the Server classpath,
|
||||
* and should be scanned for annotations/tlds/resources etc
|
||||
*
|
||||
* @return list of Bundles to be scanned and put on server classpath
|
||||
*/
|
||||
List<Bundle> getScannableBundles();
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot.utils;
|
||||
package org.eclipse.jetty.osgi.util;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.nio.file.Files;
|
|
@ -11,25 +11,138 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.osgi.boot.utils;
|
||||
package org.eclipse.jetty.osgi.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Dictionary;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.eclipse.jetty.ee9.osgi.boot.OSGiServerConstants;
|
||||
import org.eclipse.jetty.osgi.OSGiServerConstants;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.Filter;
|
||||
import org.osgi.framework.InvalidSyntaxException;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.service.packageadmin.PackageAdmin;
|
||||
|
||||
/**
|
||||
* Various useful functions utility methods for OSGi wide use.
|
||||
*/
|
||||
public class Util
|
||||
{
|
||||
/**
|
||||
* Resolve a path either absolutely or against the bundle install location, or
|
||||
* against jetty home.
|
||||
*
|
||||
* @param path the path to resolve
|
||||
* @param bundle the bundle
|
||||
* @param jettyHome the path to jetty home
|
||||
* @return the URI within the bundle as a usable URI
|
||||
*/
|
||||
public static URI resolvePathAsLocalizedURI(String path, Bundle bundle, Path jettyHome)
|
||||
throws Exception
|
||||
{
|
||||
if (StringUtil.isBlank(path))
|
||||
return null;
|
||||
|
||||
if (path.startsWith("/") || path.startsWith("file:/")) //absolute location
|
||||
return Paths.get(path).toUri();
|
||||
|
||||
//relative location
|
||||
//try inside the bundle first
|
||||
if (bundle != null)
|
||||
{
|
||||
URL url = bundle.getEntry(path);
|
||||
if (url != null)
|
||||
{
|
||||
return BundleFileLocatorHelper.DEFAULT.getLocalURL(url).toURI();
|
||||
}
|
||||
}
|
||||
|
||||
//try resolving against jetty.home
|
||||
if (jettyHome != null)
|
||||
{
|
||||
Path p = jettyHome.resolve(path);
|
||||
if (Files.exists(p))
|
||||
return p.toUri();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static URL getLocalURL(URL url)
|
||||
throws Exception
|
||||
{
|
||||
if (url == null)
|
||||
return null;
|
||||
|
||||
return BundleFileLocatorHelper.DEFAULT.getLocalURL(url);
|
||||
}
|
||||
|
||||
public static URL getLocalizedEntry(String file, Bundle bundle)
|
||||
throws Exception
|
||||
{
|
||||
if (file == null || bundle == null)
|
||||
return null;
|
||||
|
||||
URL url = bundle.getEntry(file);
|
||||
if (url == null)
|
||||
return null;
|
||||
|
||||
return BundleFileLocatorHelper.DEFAULT.getLocalURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the file system paths to bundles identified by their symbolic names.
|
||||
*
|
||||
* @param bundleSymbolicNames comma separated list of symbolic bundle names
|
||||
* @param bundleContext the bundle on whose behalf to resolve
|
||||
* @return List of resolved Paths matching the bundle symbolic names
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static List<Path> getPathsToBundlesBySymbolicNames(String bundleSymbolicNames, BundleContext bundleContext)
|
||||
throws Exception
|
||||
{
|
||||
if (bundleSymbolicNames == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
Objects.requireNonNull(bundleContext);
|
||||
|
||||
ServiceReference ref = bundleContext.getServiceReference(org.osgi.service.packageadmin.PackageAdmin.class.getName());
|
||||
PackageAdmin packageAdmin = (ref == null) ? null : (PackageAdmin)bundleContext.getService(ref);
|
||||
if (packageAdmin == null)
|
||||
throw new IllegalStateException("Unable to get PackageAdmin reference to locate required Tld bundles");
|
||||
|
||||
List<Path> paths = new ArrayList<>();
|
||||
String[] symbNames = bundleSymbolicNames.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 in manifest of " +
|
||||
bundleContext.getBundle().getSymbolicName());
|
||||
}
|
||||
|
||||
File f = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bs[0]);
|
||||
paths.add(f.toPath());
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an osgi filter for the given classname and server name.
|
||||
*
|
|
@ -28,6 +28,7 @@
|
|||
<module>jetty-jmx</module>
|
||||
<module>jetty-jndi</module>
|
||||
<module>jetty-keystore</module>
|
||||
<module>jetty-osgi</module>
|
||||
<module>jetty-proxy</module>
|
||||
<module>jetty-quic</module>
|
||||
<module>jetty-rewrite</module>
|
||||
|
@ -51,11 +52,6 @@
|
|||
<artifactId>jetty-jakarta-servlet-api</artifactId>
|
||||
<version>5.0.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee9</groupId>
|
||||
<artifactId>jetty-ee9-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
|
|
@ -578,7 +578,7 @@ public class AnnotationParser
|
|||
* @param dirResource the resource representing the baseResource being scanned (jar, dir, etc)
|
||||
* @throws Exception if unable to parse
|
||||
*/
|
||||
private void parseDir(Set<? extends Handler> handlers, Resource dirResource) throws Exception
|
||||
protected void parseDir(Set<? extends Handler> handlers, Resource dirResource) throws Exception
|
||||
{
|
||||
Path dir = dirResource.getPath();
|
||||
|
||||
|
@ -617,13 +617,13 @@ public class AnnotationParser
|
|||
* @param jarResource the jar resource to parse
|
||||
* @throws Exception if unable to parse
|
||||
*/
|
||||
private void parseJar(Set<? extends Handler> handlers, Resource jarResource) throws Exception
|
||||
protected void parseJar(Set<? extends Handler> handlers, Resource jarResource) throws Exception
|
||||
{
|
||||
if (jarResource == null)
|
||||
return;
|
||||
|
||||
if (!FileID.isJavaArchive(jarResource.getPath()))
|
||||
return;
|
||||
/* if (!FileID.isJavaArchive(jarResource.getPath()))
|
||||
return;*/
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Scanning jar {}", jarResource);
|
||||
|
@ -643,7 +643,7 @@ public class AnnotationParser
|
|||
* @param classFile the class file to parse
|
||||
* @throws IOException if unable to parse
|
||||
*/
|
||||
private void parseClass(Set<? extends Handler> handlers, Resource containingResource, Path classFile) throws IOException
|
||||
protected void parseClass(Set<? extends Handler> handlers, Resource containingResource, Path classFile) throws IOException
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Parse class from {}", classFile.toUri());
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<instructions>
|
||||
<Bundle-Description>Jetty-specific ServletContainerInitializer for Jasper</Bundle-Description>
|
||||
<Export-Package>
|
||||
org.eclipse.jetty.ee10.apache.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}", org.eclipse.jetty.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
|
||||
org.eclipse.jetty.ee10.apache.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}", org.eclipse.jetty.ee10.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
|
||||
</Export-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional
|
||||
</Require-Capability>
|
||||
|
|
|
@ -64,13 +64,14 @@
|
|||
<Export-Package>!org.example*</Export-Package>
|
||||
<!-- the test webapp is configured via a jetty xml file
|
||||
in order to add the security handler. -->
|
||||
<Web-ContextPath>/</Web-ContextPath>
|
||||
<Web-ContextPath>/ee10-demo-jetty</Web-ContextPath>
|
||||
<!-- in fact the '.' must not be there
|
||||
but Felix-BND has a bug:
|
||||
http://www.mail-archive.com/users@felix.apache.org/msg04730.html
|
||||
https://issues.apache.org/jira/browse/FELIX-1571
|
||||
-->
|
||||
<Bundle-ClassPath>.,WEB-INF/classes</Bundle-ClassPath>
|
||||
<Jetty-Environment>ee10</Jetty-Environment>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -28,8 +28,9 @@
|
|||
<instructions>
|
||||
<Import-Package>jakarta.servlet.jsp.*;version="[3,4)",org.eclipse.jetty.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))",*</Import-Package>
|
||||
<Export-Package>!org.example.*</Export-Package>
|
||||
<Web-ContextPath>/demo-jsp</Web-ContextPath>
|
||||
<Web-ContextPath>/ee10-demo-jsp</Web-ContextPath>
|
||||
<Bundle-ClassPath>.,WEB-INF/classes</Bundle-ClassPath>
|
||||
<Jetty-Environment>ee10</Jetty-Environment>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -70,9 +70,10 @@
|
|||
</Import-Package>
|
||||
<_nouses />
|
||||
<Export-Package>org.example.test;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}";-noimport:=true</Export-Package>
|
||||
<Web-ContextPath>/</Web-ContextPath>
|
||||
<Web-ContextPath>/ee10-demo-spec</Web-ContextPath>
|
||||
<Bundle-ClassPath>.,WEB-INF/classes,WEB-INF/lib</Bundle-ClassPath>
|
||||
<Jetty-ContextFilePath>/META-INF/plugin-context.xml</Jetty-ContextFilePath>
|
||||
<Jetty-ContextFilePath>META-INF/plugin-context.xml</Jetty-ContextFilePath>
|
||||
<Jetty-Environment>ee10</Jetty-Environment>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
</New>
|
||||
|
||||
<!-- ContextPath set in web.xml -->
|
||||
<Set name="war"><Property name="jetty.webapps"/>/test-spec.war</Set>
|
||||
<Set name="war"><Property name="jetty.webapps"/>/ee10-demo-spec.war</Set>
|
||||
<Set name="configurationDiscovered">true</Set>
|
||||
|
||||
<Get name="securityHandler">
|
||||
<Set name="loginService">
|
||||
<New class="org.eclipse.jetty.security.HashLoginService">
|
||||
<New class="org.eclipse.jetty.ee10.servlet.security.HashLoginService">
|
||||
<Set name="name">Test Realm</Set>
|
||||
<Set name="config"><SystemProperty name="jetty.base" default="."/>/etc/realm.properties</Set>
|
||||
</New>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
<New id="maxAmount" class="org.eclipse.jetty.plus.jndi.EnvEntry">
|
||||
<New id="maxAmount" class="org.eclipse.jetty.ee10.plus.jndi.EnvEntry">
|
||||
<Arg><Ref refid='wac'/></Arg>
|
||||
<Arg>maxAmount</Arg>
|
||||
<Arg type="java.lang.Double">100</Arg>
|
||||
|
@ -7,7 +7,7 @@
|
|||
</New>
|
||||
|
||||
|
||||
<New id="mydatasource" class="org.eclipse.jetty.plus.jndi.Resource">
|
||||
<New id="mydatasource" class="org.eclipse.jetty.ee10.plus.jndi.Resource">
|
||||
<Arg><Ref refid='wac'/></Arg>
|
||||
<Arg>jdbc/mydatasource</Arg>
|
||||
<Arg>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<description>Jetty OSGi Boot JSP bundle</description>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.boot.jsp</bundle-symbolic-name>
|
||||
<spotbugs.onlyAnalyze>org.eclipse.jetty.ee10.osgi.boot.jasper.*,org.eclipse.jetty.ee10.osgi.boot.jsp.*</spotbugs.onlyAnalyze>
|
||||
<spotbugs.onlyAnalyze>org.eclipse.jetty.ee10.osgi.boot.jsp.*</spotbugs.onlyAnalyze>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
@ -73,7 +73,6 @@
|
|||
<Bundle-Name>Jetty-OSGi-Jasper Integration</Bundle-Name>
|
||||
<Bundle-Classpath />
|
||||
<Fragment-Host>org.eclipse.jetty.ee10.osgi.boot</Fragment-Host>
|
||||
<Export-Package>!org.eclipse.jetty.ee10.osgi.boot.*</Export-Package>
|
||||
<Import-Package>
|
||||
${osgi.slf4j.import.packages},
|
||||
org.eclipse.jdt.*;resolution:=optional,
|
||||
|
@ -82,9 +81,9 @@
|
|||
com.sun.el.lang;resolution:=optional,
|
||||
com.sun.el.parser;resolution:=optional,
|
||||
com.sun.el.util;resolution:=optional,
|
||||
jakarta.el;version="[4.0,5.0)",
|
||||
jakarta.servlet;version="[$(version;==;${servletImpl.osgiVersion}),$(version;+;${servletImpl.osgiVersion}))",
|
||||
jakarta.servlet.resources;version="[$(version;==;${servletImpl.osgiVersion}),$(version;+;${servletImpl.osgiVersion}))",
|
||||
jakarta.el;version="[5.0,6.0)",
|
||||
jakarta.servlet;version="[$(version;==;${jakarta.servlet.api.version}),$(version;+;${jakarta.servlet.api.version}))",
|
||||
jakarta.servlet.resources;version="[$(version;==;${jakarta.servlet.api.version}),$(version;+;${jakarta.servlet.api.version}))",
|
||||
jakarta.servlet.jsp.resources;version="[$(version;==;${jakarta.servlet.jsp.api.version}),$(version;+;${jakarta.servlet.jsp.api.version}))",
|
||||
jakarta.servlet.jsp;version="[$(version;==;${jakarta.servlet.jsp.api.version}),$(version;+;${jakarta.servlet.jsp.api.version}))",
|
||||
jakarta.servlet.jsp.el;version="[$(version;==;${jakarta.servlet.jsp.api.version}),$(version;+;${jakarta.servlet.jsp.api.version}))",
|
||||
|
@ -100,6 +99,7 @@
|
|||
org.apache.el.parser;version="[$(version;==;${jspImpl.osgiVersion}),$(version;+;${jspImpl.osgiVersion}))";resolution:=optional,
|
||||
org.apache.jasper;version="[$(version;==;${jspImpl.osgiVersion}),$(version;+;${jspImpl.osgiVersion}))";resolution:=optional,
|
||||
org.apache.jasper.compiler;version="[$(version;==;${jspImpl.osgiVersion}),$(version;+;${jspImpl.osgiVersion}))";resolution:=optional,
|
||||
org.apache.jasper.compiler.util;version="[$(version;==;${jspImpl.osgiVersion}),$(version;+;${jspImpl.osgiVersion}))";resolution:=optional,
|
||||
org.apache.jasper.compiler.tagplugin;version="[$(version;==;${jspImpl.osgiVersion}),$(version;+;${jspImpl.osgiVersion}))";resolution:=optional,
|
||||
org.apache.jasper.runtime;version="[$(version;==;${jspImpl.osgiVersion}),$(version;+;${jspImpl.osgiVersion}))";resolution:=optional,
|
||||
org.apache.jasper.security;version="[$(version;==;${jspImpl.osgiVersion}),$(version;+;${jspImpl.osgiVersion}))";resolution:=optional,
|
||||
|
@ -131,7 +131,7 @@
|
|||
org.apache.taglibs.standard.tei;version="2.0";resolution:=optional,
|
||||
org.apache.taglibs.standard.tlv;version="2.0";resolution:=optional,
|
||||
org.apache.tomcat;version="[10,11)";resolution:=optional,
|
||||
org.eclipse.jetty.jsp;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))";resolution:=optional,
|
||||
org.eclipse.jetty.ee10.jsp;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))";resolution:=optional,
|
||||
org.osgi.*,
|
||||
org.xml.*;resolution:=optional,
|
||||
org.xml.sax.*;resolution:=optional,
|
||||
|
@ -140,7 +140,7 @@
|
|||
org.w3c.dom.ls;resolution:=optional,
|
||||
javax.xml.parser;resolution:=optional
|
||||
</Import-Package>
|
||||
<DynamicImport-Package>org.eclipse.jetty.jsp.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))",
|
||||
<DynamicImport-Package>org.eclipse.jetty.ee10.jsp.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))",
|
||||
org.apache.jasper.*;version="[$(version;===;${jspImpl.osgiVersion}),$(version;+;${jspImpl.osgiVersion}))",
|
||||
org.apache.el.*;version="[$(version;===;${jspImpl.osgiVersion}),$(version;+;${jspImpl.osgiVersion}))"
|
||||
</DynamicImport-Package>
|
||||
|
|
|
@ -1,249 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.jasper;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jakarta.servlet.jsp.JspFactory;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.JettyBootstrapActivator;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.OSGiMetaInfConfiguration;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.BundleFileLocatorHelper;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.TldBundleDiscoverer;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* ContainerTldBundleDiscoverer
|
||||
*
|
||||
* Finds bundles that are considered as on the container classpath that
|
||||
* contain tlds.
|
||||
*
|
||||
* The System property org.eclipse.jetty.ee10.osgi.tldbundles is a comma
|
||||
* separated list of exact symbolic names of bundles that have container classpath
|
||||
* tlds.
|
||||
*
|
||||
* The DeploymentManager context attribute "org.eclipse.jetty.server.webapp.containerIncludeBundlePattern"
|
||||
* can be used to define a pattern of symbolic names of bundles that contain container
|
||||
* classpath tlds.
|
||||
*
|
||||
* The matching bundles are converted to URLs that are put onto a special classloader that acts as the
|
||||
* parent classloader for contexts deployed by the jetty Server instance (see ServerInstanceWrapper).
|
||||
*
|
||||
* It also discovers the bundle that contains the jstl taglib and adds it into the
|
||||
* "org.eclipse.jetty.server.webapp.containerIncludeBundlePattern" (if it is not already there) so
|
||||
* that the WebInfOSGiConfiguration class will add the jstl taglib bundle into the list of container
|
||||
* resources.
|
||||
*
|
||||
* Eg:
|
||||
* -Dorg.eclipse.jetty.ee10.osgi.tldbundles=org.springframework.web.servlet,com.opensymphony.module.sitemesh
|
||||
*/
|
||||
public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer
|
||||
{
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ContainerTldBundleDiscoverer.class);
|
||||
|
||||
private static String DEFAULT_JSP_FACTORY_IMPL_CLASS = "org.apache.jasper.runtime.JspFactoryImpl";
|
||||
/**
|
||||
* Default name of a class that belongs to the jstl bundle. From that class
|
||||
* we locate the corresponding bundle and register it as a bundle that
|
||||
* contains tld files.
|
||||
*/
|
||||
private static String DEFAULT_JSTL_BUNDLE_CLASS = "org.apache.taglibs.standard.tag.rt.core.WhenTag";
|
||||
|
||||
private Bundle jstlBundle = null;
|
||||
|
||||
/**
|
||||
* Check the System property "org.eclipse.jetty.ee10.osgi.tldbundles" for names of
|
||||
* bundles that contain tlds and convert to URLs.
|
||||
*
|
||||
* @return The location of the jars that contain tld files as URLs.
|
||||
*/
|
||||
@Override
|
||||
public URL[] getUrlsForBundlesWithTlds(DeploymentManager deploymentManager, BundleFileLocatorHelper locatorHelper) throws Exception
|
||||
{
|
||||
if (!isJspAvailable())
|
||||
{
|
||||
return new URL[0];
|
||||
}
|
||||
|
||||
if (jstlBundle == null)
|
||||
jstlBundle = findJstlBundle();
|
||||
|
||||
final Bundle[] bundles = FrameworkUtil.getBundle(ContainerTldBundleDiscoverer.class).getBundleContext().getBundles();
|
||||
HashSet<URL> urls = new HashSet<URL>();
|
||||
String tmp = System.getProperty(OSGiMetaInfConfiguration.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(OSGiMetaInfConfiguration.CONTAINER_BUNDLE_PATTERN); //bundle name patterns
|
||||
|
||||
Pattern pattern = (tmp == null ? null : Pattern.compile(tmp));
|
||||
|
||||
//check that the jstl bundle is not already included in the pattern, and include it if it is not because
|
||||
//subsequent classes such as OSGiWebInfConfiguration use this pattern to determine which jars are
|
||||
//considered to be on the container classpath
|
||||
if (jstlBundle != null)
|
||||
{
|
||||
if (pattern == null)
|
||||
{
|
||||
pattern = Pattern.compile(jstlBundle.getSymbolicName());
|
||||
deploymentManager.setContextAttribute(OSGiMetaInfConfiguration.CONTAINER_BUNDLE_PATTERN, jstlBundle.getSymbolicName());
|
||||
}
|
||||
else if (!(pattern.matcher(jstlBundle.getSymbolicName()).matches()))
|
||||
{
|
||||
String s = tmp + "|" + jstlBundle.getSymbolicName();
|
||||
pattern = Pattern.compile(s);
|
||||
deploymentManager.setContextAttribute(OSGiMetaInfConfiguration.CONTAINER_BUNDLE_PATTERN, s);
|
||||
}
|
||||
}
|
||||
|
||||
for (Bundle bundle : bundles)
|
||||
{
|
||||
if (sysNames.contains(bundle.getSymbolicName()))
|
||||
convertBundleLocationToURL(locatorHelper, bundle, urls);
|
||||
else if (pattern != null && pattern.matcher(bundle.getSymbolicName()).matches())
|
||||
convertBundleLocationToURL(locatorHelper, bundle, urls);
|
||||
}
|
||||
|
||||
return urls.toArray(new URL[urls.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that jsp is on the classpath
|
||||
*
|
||||
* @return <code>true</code> if jsp is available in the environment
|
||||
*/
|
||||
public boolean isJspAvailable()
|
||||
{
|
||||
try
|
||||
{
|
||||
getClass().getClassLoader().loadClass("org.apache.jasper.servlet.JspServlet");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to locate the JspServlet: jsp support unavailable.", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some versions of JspFactory do Class.forName, which probably won't work in an
|
||||
* OSGi environment.
|
||||
*/
|
||||
public void fixJspFactory()
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<jakarta.servlet.ServletContext> servletContextClass = jakarta.servlet.ServletContext.class;
|
||||
// bug #299733
|
||||
JspFactory fact = JspFactory.getDefaultFactory();
|
||||
if (fact == null)
|
||||
{ // bug #299733
|
||||
// JspFactory does a simple
|
||||
// Class.getForName("org.apache.jasper.runtime.JspFactoryImpl")
|
||||
// however its bundles does not import the jasper package
|
||||
// so it fails. let's help things out:
|
||||
fact = (JspFactory)JettyBootstrapActivator.class.getClassLoader()
|
||||
.loadClass(DEFAULT_JSP_FACTORY_IMPL_CLASS).getDeclaredConstructor().newInstance();
|
||||
JspFactory.setDefaultFactory(fact);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to set the JspFactory: jsp support incomplete.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the bundle that contains a jstl implementation class, which assumes that
|
||||
* the jstl taglibs will be inside the same bundle.
|
||||
*
|
||||
* @return Bundle contains the jstl implementation class
|
||||
*/
|
||||
public Bundle findJstlBundle()
|
||||
{
|
||||
Class<?> jstlClass = null;
|
||||
|
||||
try
|
||||
{
|
||||
jstlClass = JSTLBundleDiscoverer.class.getClassLoader().loadClass(DEFAULT_JSTL_BUNDLE_CLASS);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
LOG.info("jstl not on classpath", e);
|
||||
}
|
||||
|
||||
if (jstlClass != null)
|
||||
//get the bundle containing jstl
|
||||
return FrameworkUtil.getBundle(jstlClass);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a bundle that contains tld files as a URL. The URLs are
|
||||
* used by jasper to discover the tld files.
|
||||
*
|
||||
* Support only 2 types of packaging for the bundle: - the bundle is a jar
|
||||
* (recommended for runtime.) - the bundle is a folder and contain jars in
|
||||
* the root and/or in the lib folder (nice for PDE development situations)
|
||||
* Unsupported: the bundle is a jar that embeds more jars.
|
||||
*/
|
||||
private void convertBundleLocationToURL(BundleFileLocatorHelper locatorHelper, Bundle bundle, Set<URL> urls) throws Exception
|
||||
{
|
||||
File jasperLocation = locatorHelper.getBundleInstallLocation(bundle);
|
||||
if (jasperLocation.isDirectory())
|
||||
{
|
||||
for (File f : jasperLocation.listFiles())
|
||||
{
|
||||
if (FileID.isJavaArchive(f.getName()) && f.isFile())
|
||||
{
|
||||
urls.add(f.toURI().toURL());
|
||||
}
|
||||
else if (f.isDirectory() && f.getName().equals("lib"))
|
||||
{
|
||||
for (File f2 : jasperLocation.listFiles())
|
||||
{
|
||||
if (FileID.isJavaArchive(f2.getName()) && f2.isFile())
|
||||
{
|
||||
urls.add(f2.toURI().toURL());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
urls.add(jasperLocation.toURI().toURL());
|
||||
}
|
||||
else
|
||||
{
|
||||
urls.add(jasperLocation.toURI().toURL());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.jasper;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.servlet.jsp.JspFactory;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.JettyBootstrapActivator;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.BundleFileLocatorHelper;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.TldBundleDiscoverer;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* JSTLBundleDiscoverer
|
||||
*
|
||||
* Fix various shortcomings with the way jasper parses the tld files. Plugs the
|
||||
* JSTL tlds assuming that they are packaged with the bundle that contains the
|
||||
* JSTL classes.
|
||||
* <p>
|
||||
* Pluggable tlds at the server level are handled by
|
||||
* {@link ContainerTldBundleDiscoverer}.
|
||||
* </p>
|
||||
*/
|
||||
public class JSTLBundleDiscoverer implements TldBundleDiscoverer
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JSTLBundleDiscoverer.class);
|
||||
|
||||
/**
|
||||
* Default name of a class that belongs to the jstl bundle. From that class
|
||||
* we locate the corresponding bundle and register it as a bundle that
|
||||
* contains tld files.
|
||||
*/
|
||||
private static String DEFAULT_JSTL_BUNDLE_CLASS = "org.apache.taglibs.standard.tag.el.core.WhenTag";
|
||||
|
||||
/**
|
||||
* Default jsp factory implementation. Idally jasper is osgified and we can
|
||||
* use services. In the mean time we statically set the jsp factory
|
||||
* implementation. bug #299733
|
||||
*/
|
||||
private static String DEFAULT_JSP_FACTORY_IMPL_CLASS = "org.apache.jasper.runtime.JspFactoryImpl";
|
||||
|
||||
private static final Set<URL> __tldBundleCache = new HashSet<URL>();
|
||||
|
||||
public JSTLBundleDiscoverer()
|
||||
{
|
||||
try
|
||||
{
|
||||
// sanity check:
|
||||
Class cl = getClass().getClassLoader().loadClass("org.apache.jasper.servlet.JspServlet");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to locate the JspServlet: jsp support unavailable.", e);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
Class<jakarta.servlet.ServletContext> servletContextClass = jakarta.servlet.ServletContext.class;
|
||||
// bug #299733
|
||||
JspFactory fact = JspFactory.getDefaultFactory();
|
||||
if (fact == null)
|
||||
{ // bug #299733
|
||||
// JspFactory does a simple
|
||||
// Class.getForName("org.apache.jasper.runtime.JspFactoryImpl")
|
||||
// however its bundles does not import the jasper package
|
||||
// so it fails. let's help things out:
|
||||
fact = (JspFactory)JettyBootstrapActivator.class.getClassLoader()
|
||||
.loadClass(DEFAULT_JSP_FACTORY_IMPL_CLASS).getDeclaredConstructor().newInstance();
|
||||
JspFactory.setDefaultFactory(fact);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to set the JspFactory: jsp support incomplete.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The jasper TldScanner expects a URLClassloader to parse a jar for the
|
||||
* /META-INF/*.tld it may contain. We place the bundles that we know contain
|
||||
* such tag-libraries. Please note that it will work if and only if the
|
||||
* bundle is a jar (!) Currently we just hardcode the bundle that contains
|
||||
* the jstl implemenation.
|
||||
*
|
||||
* A workaround when the tld cannot be parsed with this method is to copy
|
||||
* and paste it inside the WEB-INF of the webapplication where it is used.
|
||||
*
|
||||
* Support only 2 types of packaging for the bundle: - the bundle is a jar
|
||||
* (recommended for runtime.) - the bundle is a folder and contain jars in
|
||||
* the root and/or in the lib folder (nice for PDE development situations)
|
||||
* Unsupported: the bundle is a jar that embeds more jars.
|
||||
*
|
||||
* @return array of URLs
|
||||
* @throws Exception In case of errors during resolving TLDs files
|
||||
*/
|
||||
@Override
|
||||
public URL[] getUrlsForBundlesWithTlds(DeploymentManager deployer, BundleFileLocatorHelper locatorHelper) throws Exception
|
||||
{
|
||||
|
||||
ArrayList<URL> urls = new ArrayList<URL>();
|
||||
Class<?> jstlClass = null;
|
||||
|
||||
// Look for the jstl bundle
|
||||
// We assume the jstl's tlds are defined there.
|
||||
// We assume that the jstl bundle is imported by this bundle
|
||||
// So we can look for this class using this bundle's classloader:
|
||||
try
|
||||
{
|
||||
jstlClass = JSTLBundleDiscoverer.class.getClassLoader().loadClass(DEFAULT_JSTL_BUNDLE_CLASS);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
LOG.info("jstl not on classpath", e);
|
||||
}
|
||||
|
||||
if (jstlClass != null)
|
||||
{
|
||||
//get the bundle containing jstl
|
||||
Bundle tldBundle = FrameworkUtil.getBundle(jstlClass);
|
||||
File tldBundleLocation = locatorHelper.getBundleInstallLocation(tldBundle);
|
||||
|
||||
if (tldBundleLocation != null && tldBundleLocation.isDirectory())
|
||||
{
|
||||
// try to find the jar files inside this folder
|
||||
for (File f : tldBundleLocation.listFiles())
|
||||
{
|
||||
if (FileID.isJavaArchive(f.getName()) && f.isFile())
|
||||
{
|
||||
urls.add(f.toURI().toURL());
|
||||
}
|
||||
else if (f.isDirectory() && f.getName().equals("lib"))
|
||||
{
|
||||
for (File f2 : tldBundleLocation.listFiles())
|
||||
{
|
||||
if (FileID.isJavaArchive(f2.getName()) && f2.isFile())
|
||||
{
|
||||
urls.add(f2.toURI().toURL());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tldBundleLocation != null)
|
||||
{
|
||||
urls.add(tldBundleLocation.toURI().toURL());
|
||||
|
||||
String pattern = (String)deployer.getContextAttribute("org.eclipse.jetty.server.webapp.containerIncludeBundlePattern");
|
||||
pattern = (pattern == null ? "" : pattern);
|
||||
if (!pattern.contains(tldBundle.getSymbolicName()))
|
||||
{
|
||||
pattern += "|" + tldBundle.getSymbolicName();
|
||||
deployer.setContextAttribute("org.eclipse.jetty.server.webapp.containerIncludeBundlePattern", pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return urls.toArray(new URL[urls.size()]);
|
||||
}
|
||||
}
|
|
@ -13,8 +13,8 @@
|
|||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.jsp;
|
||||
|
||||
import org.eclipse.jetty.ee10.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.jasper.ContainerTldBundleDiscoverer;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.EE10Activator;
|
||||
import org.eclipse.jetty.osgi.util.ServerClasspathContributor;
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
|
@ -24,10 +24,9 @@ import org.osgi.framework.BundleContext;
|
|||
* Sets up support for jsp and jstl. All relevant jsp jars must also be installed
|
||||
* into the osgi environment.
|
||||
* <p>
|
||||
* Note that as this is part of a bundle fragment, this activator is NOT
|
||||
* called by the OSGi environment. Instead, the org.eclipse.jetty.ee10.osgi.boot.utils.internal.PackageAdminTracker
|
||||
* simulates fragment activation and causes this class's start() method to
|
||||
* be called.
|
||||
* NOTE that as this is part of a bundle fragment, this activator is NOT
|
||||
* called by the OSGi environment. Instead, the org.eclipse.jetty.osgi.util.internal.PackageAdminTracker
|
||||
* simulates fragment activation and causes this class's start() method to be called.
|
||||
* </p>
|
||||
* <p>
|
||||
* The package of this class MUST match the Bundle-SymbolicName of this fragment
|
||||
|
@ -36,24 +35,21 @@ import org.osgi.framework.BundleContext;
|
|||
*/
|
||||
public class FragmentActivator implements BundleActivator
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
ServerClasspathContributor _tldClasspathContributor;
|
||||
|
||||
@Override
|
||||
public void start(BundleContext context) throws Exception
|
||||
{
|
||||
//set up some classes that will look for bundles with tlds that must be converted
|
||||
//to urls and treated as if they are on the Jetty container's classpath so that
|
||||
//jasper can deal with them
|
||||
ServerInstanceWrapper.addContainerTldBundleDiscoverer(new ContainerTldBundleDiscoverer());
|
||||
//Register a class that will provide the identity of bundles that
|
||||
//contain TLDs and therefore need to be scanned.
|
||||
_tldClasspathContributor = new TLDServerClasspathContributor();
|
||||
EE10Activator.registerServerClasspathContributor(_tldClasspathContributor);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception
|
||||
{
|
||||
|
||||
EE10Activator.unregisterServerClasspathContributor(_tldClasspathContributor);
|
||||
_tldClasspathContributor = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.jsp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.ee10.osgi.boot.OSGiMetaInfConfiguration;
|
||||
import org.eclipse.jetty.osgi.util.ServerClasspathContributor;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
|
||||
/**
|
||||
* @author janb
|
||||
*
|
||||
*/
|
||||
public class TLDServerClasspathContributor implements ServerClasspathContributor
|
||||
{
|
||||
|
||||
/**
|
||||
* Name of a class that belongs to the jstl bundle. From that class
|
||||
* we locate the corresponding bundle.
|
||||
*/
|
||||
private static String JSTL_BUNDLE_CLASS = "org.apache.taglibs.standard.tag.el.core.WhenTag";
|
||||
|
||||
@Override
|
||||
public List<Bundle> getScannableBundles()
|
||||
{
|
||||
if (!isJspAvailable())
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Bundle> scannableBundles = new ArrayList<>();
|
||||
List<String> bundleNames = Collections.emptyList();
|
||||
|
||||
String tmp = System.getProperty(OSGiMetaInfConfiguration.SYS_PROP_TLD_BUNDLES); //comma separated exact names
|
||||
|
||||
if (tmp != null)
|
||||
{
|
||||
String[] names = tmp.split(", \n\r\t");
|
||||
bundleNames = Arrays.asList(names);
|
||||
}
|
||||
|
||||
Bundle jstlBundle = findJstlBundle();
|
||||
if (jstlBundle != null)
|
||||
scannableBundles.add(jstlBundle);
|
||||
|
||||
final Bundle[] bundles = FrameworkUtil.getBundle(getClass()).getBundleContext().getBundles();
|
||||
for (Bundle bundle : bundles)
|
||||
{
|
||||
if (bundleNames.contains(bundle.getSymbolicName()))
|
||||
scannableBundles.add(bundle);
|
||||
}
|
||||
|
||||
return scannableBundles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that jsp is on the classpath
|
||||
*
|
||||
* @return <code>true</code> if jsp is available in the environment
|
||||
*/
|
||||
public boolean isJspAvailable()
|
||||
{
|
||||
try
|
||||
{
|
||||
getClass().getClassLoader().loadClass("org.apache.jasper.servlet.JspServlet");
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the bundle that contains a jstl implementation class, which assumes that
|
||||
* the jstl taglibs will be inside the same bundle.
|
||||
*
|
||||
* @return Bundle contains the jstl implementation class
|
||||
*/
|
||||
public Bundle findJstlBundle()
|
||||
{
|
||||
Class<?> jstlClass = null;
|
||||
|
||||
try
|
||||
{
|
||||
jstlClass = getClass().getClassLoader().loadClass(JSTL_BUNDLE_CLASS);
|
||||
return FrameworkUtil.getBundle(jstlClass);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
//no jstl do nothing
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -12,12 +12,6 @@
|
|||
<Set name="contexts">
|
||||
<Ref refid="Contexts" />
|
||||
</Set>
|
||||
<!--
|
||||
<Call name="setContextAttribute">
|
||||
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
|
||||
<Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg>
|
||||
</Call>
|
||||
-->
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -37,18 +37,7 @@
|
|||
</Set>
|
||||
</New>
|
||||
</Set>
|
||||
<!--
|
||||
<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
|
||||
<Set name="secureScheme">https</Set>
|
||||
<Set name="securePort"><Property name="jetty.httpConfig.securePort" default="8443" /></Set>
|
||||
<Set name="outputBufferSize">32768</Set>
|
||||
<Set name="requestHeaderSize">8192</Set>
|
||||
<Set name="responseHeaderSize">8192</Set>
|
||||
<Set name="sendServerVersion">true</Set>
|
||||
<Set name="sendDateHeader">false</Set>
|
||||
<Set name="headerCacheSize">1024</Set>
|
||||
</New>
|
||||
-->
|
||||
|
||||
<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
|
||||
<Set name="secureScheme"><Property name="jetty.httpConfig.secureScheme" default="https" /></Set>
|
||||
<Set name="securePort"><Property name="jetty.httpConfig.securePort" default="8443" /></Set>
|
||||
|
@ -75,33 +64,6 @@
|
|||
<Set name="dumpBeforeStop"><Property name="jetty.server.dumpBeforeStop" default="false"/></Set>
|
||||
|
||||
|
||||
<Call class="org.eclipse.jetty.ee10.webapp.Configurations" name="setServerDefault">
|
||||
<Arg><Ref refid="Server"/></Arg>
|
||||
<Call name="add">
|
||||
<Arg name="configClass">
|
||||
<Array type="String">
|
||||
<Item>org.eclipse.jetty.ee10.webapp.FragmentConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.ee10.webapp.JettyWebXmlConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.ee10.webapp.WebXmlConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.ee10.webapp.WebAppConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.ee10.webapp.ServletsConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.ee10.webapp.JspConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.ee10.webapp.JaasConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.ee10.webapp.JndiConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.ee10.webapp.JmxConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.ee10.osgi.annotations.AnnotationConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.websocket.server.config.JettyWebSocketConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.websocket.jakarta.server.config.JakartaWebSocketConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.ee10.osgi.boot.OSGiWebInfConfiguration</Item>
|
||||
<Item>org.eclipse.jetty.ee10.osgi.boot.OSGiMetaInfConfiguration</Item>
|
||||
</Array>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Call>
|
||||
|
||||
|
||||
<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>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
<artifactId>jetty-osgi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -41,9 +41,26 @@
|
|||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.service.cm</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.service.event</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.util.tracker</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
|
@ -73,8 +90,8 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>org.eclipse.jetty.ee10.osgi.boot;singleton:=true</Bundle-SymbolicName>
|
||||
<Bundle-Activator>org.eclipse.jetty.ee10.osgi.boot.JettyBootstrapActivator</Bundle-Activator>
|
||||
<DynamicImport-Package>org.eclipse.jetty.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))"</DynamicImport-Package>
|
||||
<Bundle-Activator>org.eclipse.jetty.ee10.osgi.boot.EE10Activator</Bundle-Activator>
|
||||
<DynamicImport-Package>org.eclipse.jetty.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))", org.eclipse.jetty.ee10.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))"</DynamicImport-Package>
|
||||
<Import-Package>
|
||||
${osgi.slf4j.import.packages},
|
||||
jakarta.mail;version="2.0";resolution:=optional,
|
||||
|
@ -82,21 +99,22 @@
|
|||
jakarta.mail.internet;version="2.0";resolution:=optional,
|
||||
jakarta.mail.search;version="2.0";resolution:=optional,
|
||||
jakarta.mail.util;version="2.0";resolution:=optional,
|
||||
jakarta.servlet;version="[$(version;==;${servletImpl.osgiVersion}),$(version;+;${servletImpl.osgiVersion}))",
|
||||
jakarta.servlet.http;version="[$(version;==;${servletImpl.osgiVersion}),$(version;+;${servletImpl.osgiVersion}))",
|
||||
jakarta.servlet;version="[$(version;==;${jakarta.servlet.api.version}),$(version;+;${jakarta.servlet.api.version}))",
|
||||
jakarta.servlet.http;version="[$(version;==;${jakarta.servlet.api.version}),$(version;+;${jakarta.servlet.api.version}))",
|
||||
jakarta.transaction;version="2.0.0";resolution:=optional,
|
||||
jakarta.transaction.xa;version="2.0.0";resolution:=optional,
|
||||
org.objectweb.asm;version="$(version;=;${asm.version})";resolution:=optional,
|
||||
org.osgi.framework,
|
||||
org.osgi.service.cm;version="1.4.0",
|
||||
org.osgi.service.event;version="1.4.0",
|
||||
org.osgi.service.cm;version="${osgi-service-cm-version}",
|
||||
org.osgi.service.component;version="${osgi-service-component-version}",
|
||||
org.osgi.service.event;version="${osgi-service-event-version}",
|
||||
org.osgi.service.packageadmin,
|
||||
org.osgi.service.startlevel;version="1.0.0",
|
||||
org.osgi.service.url;version="1.0.0",
|
||||
org.osgi.util.tracker;version="1.3.0",
|
||||
org.osgi.util.tracker;version="${osgi-util-tracker-version}",
|
||||
org.xml.sax,
|
||||
org.xml.sax.helpers,
|
||||
org.eclipse.jetty.annotations;resolution:=optional,
|
||||
org.eclipse.jetty.ee10.annotations;resolution:=optional,
|
||||
*
|
||||
</Import-Package>
|
||||
<Require-Capability>
|
||||
|
|
|
@ -13,19 +13,21 @@
|
|||
|
||||
package org.eclipse.jetty.ee10.osgi.annotations;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.servlet.ServletContainerInitializer;
|
||||
import org.eclipse.jetty.ee10.annotations.AnnotationConfiguration.ParserTask;
|
||||
import org.eclipse.jetty.ee10.annotations.AnnotationConfiguration.TimeStatistic;
|
||||
import org.eclipse.jetty.ee10.annotations.AnnotationParser.Handler;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.OSGiMetaInfConfiguration;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.OSGiWebappConstants;
|
||||
import org.eclipse.jetty.ee10.webapp.Configuration;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.osgi.OSGiWebappConstants;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
import org.eclipse.jetty.util.statistic.CounterStatistic;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.Constants;
|
||||
|
@ -80,18 +82,18 @@ public class AnnotationConfiguration extends org.eclipse.jetty.ee10.annotations.
|
|||
* This parser scans the bundles using the OSGi APIs instead of assuming a jar.
|
||||
*/
|
||||
@Override
|
||||
protected org.eclipse.jetty.ee10.annotations.AnnotationParser createAnnotationParser(int javaTargetVersion)
|
||||
protected org.eclipse.jetty.ee10.annotations.AnnotationParser createAnnotationParser(int platform)
|
||||
{
|
||||
return new AnnotationParser(javaTargetVersion);
|
||||
return new AnnotationParser(platform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getJarFor(ServletContainerInitializer service) throws MalformedURLException, IOException
|
||||
public Resource getJarFor(ServletContainerInitializer service)
|
||||
{
|
||||
Resource resource = super.getJarFor(service);
|
||||
// TODO This is not correct, but implemented like this to be bug for bug compatible
|
||||
// with previous implementation that could only handle actual jars and not bundles.
|
||||
if (resource != null && !FileID.isJavaArchive(resource.getFileName()))
|
||||
if (resource != null && !FileID.isJavaArchive(resource.getURI()))
|
||||
return null;
|
||||
return resource;
|
||||
}
|
||||
|
@ -127,7 +129,7 @@ public class AnnotationConfiguration extends org.eclipse.jetty.ee10.annotations.
|
|||
if (bundle.getState() == Bundle.UNINSTALLED)
|
||||
continue;
|
||||
|
||||
Resource bundleRes = oparser.indexBundle(bundle);
|
||||
Resource bundleRes = oparser.indexBundle(ResourceFactory.of(context), bundle);
|
||||
if (!context.getMetaData().getWebInfResources(false).contains(bundleRes))
|
||||
{
|
||||
context.getMetaData().addWebInfResource(bundleRes);
|
||||
|
@ -142,7 +144,7 @@ public class AnnotationConfiguration extends org.eclipse.jetty.ee10.annotations.
|
|||
}
|
||||
}
|
||||
//scan ourselves
|
||||
oparser.indexBundle(webbundle);
|
||||
oparser.indexBundle(ResourceFactory.of(context), webbundle);
|
||||
parseWebBundle(context, oparser, webbundle);
|
||||
_webInfLibStats.increment();
|
||||
|
||||
|
|
|
@ -14,50 +14,54 @@
|
|||
package org.eclipse.jetty.ee10.osgi.annotations;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.osgi.util.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.Constants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class AnnotationParser extends org.eclipse.jetty.ee10.annotations.AnnotationParser
|
||||
{
|
||||
private Set<URI> _alreadyParsed = ConcurrentHashMap.newKeySet();
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AnnotationParser.class);
|
||||
|
||||
private Set<URI> _parsed = ConcurrentHashMap.newKeySet();
|
||||
|
||||
private ConcurrentHashMap<URI, Bundle> _uriToBundle = new ConcurrentHashMap<>();
|
||||
private ConcurrentHashMap<Bundle, Resource> _bundleToResource = new ConcurrentHashMap<>();
|
||||
private ConcurrentHashMap<Resource, Bundle> _resourceToBundle = new ConcurrentHashMap<>();
|
||||
private ConcurrentHashMap<Bundle, URI> _bundleToUri = new ConcurrentHashMap<>();
|
||||
|
||||
public AnnotationParser(int javaPlatform)
|
||||
public AnnotationParser()
|
||||
{
|
||||
super(javaPlatform);
|
||||
super();
|
||||
}
|
||||
|
||||
public AnnotationParser(int platform)
|
||||
{
|
||||
super(platform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep track of a jetty URI Resource and its associated OSGi bundle.
|
||||
*
|
||||
*@param resourceFactory the ResourceFactory to convert bundle location
|
||||
* @param bundle the bundle to index
|
||||
* @return the resource for the bundle
|
||||
* @throws Exception if unable to create the resource reference
|
||||
*/
|
||||
public Resource indexBundle(Bundle bundle) throws Exception
|
||||
public Resource indexBundle(ResourceFactory resourceFactory, Bundle bundle) throws Exception
|
||||
{
|
||||
File bundleFile = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bundle);
|
||||
Resource resource = Resource.newResource(bundleFile.toURI());
|
||||
Resource resource = resourceFactory.newResource(bundleFile.toURI());
|
||||
URI uri = resource.getURI();
|
||||
_uriToBundle.putIfAbsent(uri, bundle);
|
||||
_bundleToUri.putIfAbsent(bundle, uri);
|
||||
|
@ -81,145 +85,57 @@ public class AnnotationParser extends org.eclipse.jetty.ee10.annotations.Annotat
|
|||
return _resourceToBundle.get(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void parse(Set<? extends Handler> handlers, URI[] uris)
|
||||
throws Exception
|
||||
{
|
||||
for (URI uri : uris)
|
||||
{
|
||||
Bundle associatedBundle = _uriToBundle.get(uri);
|
||||
if (associatedBundle == null)
|
||||
{
|
||||
if (!_alreadyParsed.add(uri))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//a jar in WEB-INF/lib or the WEB-INF/classes
|
||||
//use the behavior of the super class for a standard jar.
|
||||
super.parse(handlers, new URI[]{uri});
|
||||
}
|
||||
else
|
||||
{
|
||||
parse(handlers, associatedBundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void parse(Set<? extends Handler> handlers, Bundle bundle)
|
||||
throws Exception
|
||||
{
|
||||
URI uri = _bundleToUri.get(bundle);
|
||||
if (!_alreadyParsed.add(uri))
|
||||
{
|
||||
|
||||
Resource bundleResource = _bundleToResource.get(bundle);
|
||||
if (bundleResource == null)
|
||||
return;
|
||||
|
||||
//if already added, it is already parsed
|
||||
if (!_parsed.add(_bundleToUri.get(bundle)))
|
||||
return;
|
||||
|
||||
parse(handlers, bundleResource);
|
||||
}
|
||||
|
||||
String bundleClasspath = (String)bundle.getHeaders().get(Constants.BUNDLE_CLASSPATH);
|
||||
if (bundleClasspath == null)
|
||||
{
|
||||
bundleClasspath = ".";
|
||||
}
|
||||
//order the paths first by the number of tokens in the path second alphabetically.
|
||||
TreeSet<String> paths = new TreeSet<>(
|
||||
new Comparator<String>()
|
||||
{
|
||||
@Override
|
||||
public int compare(String o1, String o2)
|
||||
public void parse(final Set<? extends Handler> handlers, Resource r) throws Exception
|
||||
{
|
||||
int paths1 = new StringTokenizer(o1, "/", false).countTokens();
|
||||
int paths2 = new StringTokenizer(o2, "/", false).countTokens();
|
||||
if (paths1 == paths2)
|
||||
{
|
||||
return o1.compareTo(o2);
|
||||
}
|
||||
return paths2 - paths1;
|
||||
}
|
||||
});
|
||||
boolean hasDotPath = false;
|
||||
StringTokenizer tokenizer = new StringTokenizer(bundleClasspath, StringUtil.DEFAULT_DELIMS, false);
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String token = tokenizer.nextToken().trim();
|
||||
if (!token.startsWith("/"))
|
||||
{
|
||||
token = "/" + token;
|
||||
}
|
||||
if (token.equals("/."))
|
||||
{
|
||||
hasDotPath = true;
|
||||
}
|
||||
else if (!FileID.isJavaArchive(token) && !token.endsWith("/"))
|
||||
{
|
||||
paths.add(token + "/");
|
||||
}
|
||||
else
|
||||
{
|
||||
paths.add(token);
|
||||
}
|
||||
}
|
||||
//support the development environment: maybe the classes are inside bin or target/classes
|
||||
//this is certainly not useful in production.
|
||||
//however it makes our life so much easier during development.
|
||||
if (bundle.getEntry("/.classpath") != null)
|
||||
{
|
||||
if (bundle.getEntry("/bin/") != null)
|
||||
{
|
||||
paths.add("/bin/");
|
||||
}
|
||||
else if (bundle.getEntry("/target/classes/") != null)
|
||||
{
|
||||
paths.add("/target/classes/");
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("rawtypes")
|
||||
Enumeration classes = bundle.findEntries("/", "*.class", true);
|
||||
if (classes == null)
|
||||
if (r == null)
|
||||
return;
|
||||
|
||||
if (!r.exists())
|
||||
return;
|
||||
|
||||
if (FileID.isJavaArchive(r.getPath()))
|
||||
{
|
||||
parseJar(handlers, r);
|
||||
return;
|
||||
}
|
||||
while (classes.hasMoreElements())
|
||||
|
||||
if (r.isDirectory())
|
||||
{
|
||||
URL classUrl = (URL)classes.nextElement();
|
||||
String path = classUrl.getPath();
|
||||
//remove the longest path possible:
|
||||
String name = null;
|
||||
for (String prefixPath : paths)
|
||||
{
|
||||
if (path.startsWith(prefixPath))
|
||||
{
|
||||
name = path.substring(prefixPath.length());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (name == null && hasDotPath)
|
||||
{
|
||||
//remove the starting '/'
|
||||
name = path.substring(1);
|
||||
}
|
||||
if (name == null)
|
||||
{
|
||||
//found some .class file in the archive that was not under one of the prefix paths
|
||||
//or the bundle classpath wasn't simply ".", so skip it
|
||||
continue;
|
||||
parseDir(handlers, r);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isValidClassFileName(name))
|
||||
if (FileID.isClassFile(r.getPath()))
|
||||
{
|
||||
continue; //eg skip module-info.class
|
||||
parseClass(handlers, null, r.getPath());
|
||||
}
|
||||
|
||||
//transform into a classname to pass to the resolver
|
||||
String shortName = StringUtil.replace(name, '/', '.').substring(0, name.length() - 6);
|
||||
|
||||
addParsedClass(shortName, getResource(bundle));
|
||||
|
||||
try (InputStream classInputStream = classUrl.openStream())
|
||||
//Not already parsed, it could be a file that actually is compressed but does not have
|
||||
//.jar/.zip etc extension, such as equinox urls, so try to parse it
|
||||
try
|
||||
{
|
||||
scanClass(handlers, getResource(bundle), classInputStream);
|
||||
parseJar(handlers, r);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.warn("Resource not able to be scanned for classes: {}", r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,235 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.OSGiClassLoader;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.resource.JarResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* AbstractContextProvider
|
||||
*
|
||||
* Base class for DeploymentManager Providers that can deploy ContextHandlers into
|
||||
* Jetty that have been discovered via OSGI either as bundles or services.
|
||||
*/
|
||||
public abstract class AbstractContextProvider extends AbstractLifeCycle implements AppProvider
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractContextProvider.class);
|
||||
|
||||
private DeploymentManager _deploymentManager;
|
||||
|
||||
private ServerInstanceWrapper _serverWrapper;
|
||||
|
||||
/**
|
||||
* OSGiApp
|
||||
*/
|
||||
public class OSGiApp extends AbstractOSGiApp
|
||||
{
|
||||
private String _contextFile;
|
||||
private ContextHandler _contextHandler;
|
||||
private boolean _configured = false;
|
||||
|
||||
public OSGiApp(DeploymentManager manager, AppProvider provider, String originId, Bundle bundle, String contextFile)
|
||||
{
|
||||
super(manager, provider, bundle, originId);
|
||||
_contextFile = contextFile;
|
||||
}
|
||||
|
||||
public OSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String contextFile, String originId)
|
||||
{
|
||||
super(manager, provider, bundle, properties, originId);
|
||||
_contextFile = contextFile;
|
||||
}
|
||||
|
||||
public String getContextFile()
|
||||
{
|
||||
return _contextFile;
|
||||
}
|
||||
|
||||
public void setHandler(ContextHandler h)
|
||||
{
|
||||
_contextHandler = h;
|
||||
}
|
||||
|
||||
public ContextHandler createContextHandler()
|
||||
throws Exception
|
||||
{
|
||||
configureContextHandler();
|
||||
return _contextHandler;
|
||||
}
|
||||
|
||||
public void configureContextHandler()
|
||||
throws Exception
|
||||
{
|
||||
if (_configured)
|
||||
return;
|
||||
|
||||
_configured = true;
|
||||
|
||||
//Override for bundle root may have been set
|
||||
String bundleOverrideLocation = (String)_properties.get(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE);
|
||||
|
||||
//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.getResourceBase() == null)
|
||||
{
|
||||
_contextHandler.setResourceBase(rootResource.getPath());
|
||||
}
|
||||
|
||||
//Use a classloader that knows about the common jetty parent loader, and also the bundle
|
||||
OSGiClassLoader classLoader = new OSGiClassLoader(getServerInstanceWrapper().getParentClassLoaderForWebapps(), _bundle);
|
||||
|
||||
//if there is a context file, find it and apply it
|
||||
if (_contextFile == null && _contextHandler == null)
|
||||
throw new IllegalStateException("No context file or ContextHandler");
|
||||
|
||||
if (_contextFile != null)
|
||||
{
|
||||
//apply the contextFile, creating the ContextHandler, the DeploymentManager will register it in the ContextHandlerCollection
|
||||
Resource res = null;
|
||||
|
||||
String jettyHome = (String)getServerInstanceWrapper().getServer().getAttribute(OSGiServerConstants.JETTY_HOME);
|
||||
if (jettyHome == null)
|
||||
jettyHome = System.getProperty(OSGiServerConstants.JETTY_HOME);
|
||||
|
||||
res = findFile(_contextFile, jettyHome, bundleOverrideLocation, _bundle);
|
||||
|
||||
//apply the context xml file, either to an existing ContextHandler, or letting the
|
||||
//it create the ContextHandler as necessary
|
||||
if (res != null)
|
||||
{
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Context classloader = {}", cl);
|
||||
try
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(res);
|
||||
HashMap properties = new HashMap();
|
||||
//put the server instance in
|
||||
properties.put("Server", getServerInstanceWrapper().getServer());
|
||||
//put in the location of the bundle root
|
||||
properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString());
|
||||
|
||||
// insert the bundle's location as a property.
|
||||
xmlConfiguration.getProperties().putAll(properties);
|
||||
|
||||
if (_contextHandler == null)
|
||||
_contextHandler = (ContextHandler)xmlConfiguration.configure();
|
||||
else
|
||||
xmlConfiguration.configure(_contextHandler);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Set up the class loader we created
|
||||
_contextHandler.setClassLoader(classLoader);
|
||||
|
||||
//If a bundle/service property specifies context path, let it override the context xml
|
||||
String contextPath = (String)_properties.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
|
||||
if (contextPath != null)
|
||||
_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
|
||||
|
||||
if (_contextHandler instanceof ServletContextHandler servletContextHandler)
|
||||
{
|
||||
String[] targets = servletContextHandler.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);
|
||||
servletContextHandler.setProtectedTargets(updatedTargets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AbstractContextProvider(ServerInstanceWrapper wrapper)
|
||||
{
|
||||
_serverWrapper = wrapper;
|
||||
}
|
||||
|
||||
public ServerInstanceWrapper getServerInstanceWrapper()
|
||||
{
|
||||
return _serverWrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeploymentManager(DeploymentManager deploymentManager)
|
||||
{
|
||||
_deploymentManager = deploymentManager;
|
||||
}
|
||||
|
||||
public DeploymentManager getDeploymentManager()
|
||||
{
|
||||
return _deploymentManager;
|
||||
}
|
||||
}
|
|
@ -1,195 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
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.eclipse.jetty.util.resource.Resource;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* AbstractOSGiApp
|
||||
*
|
||||
* Base class representing info about a webapp/ContextHandler that is deployed into Jetty.
|
||||
*/
|
||||
public abstract class AbstractOSGiApp extends App
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractOSGiApp.class);
|
||||
|
||||
protected Bundle _bundle;
|
||||
protected Dictionary<?, ?> _properties;
|
||||
protected ServiceRegistration _registration;
|
||||
|
||||
public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, String originId)
|
||||
{
|
||||
this(manager, provider, bundle, bundle.getHeaders(), originId);
|
||||
}
|
||||
|
||||
public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary<?, ?> properties, String originId)
|
||||
{
|
||||
super(manager, provider, null, originId); // TODO environment
|
||||
_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;
|
||||
}
|
||||
|
||||
protected 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;
|
||||
}
|
||||
|
||||
protected 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;
|
||||
}
|
||||
|
||||
protected Resource findFile(String fileName, String jettyHome, String bundleOverrideLocation, Bundle containingBundle)
|
||||
{
|
||||
Resource res = null;
|
||||
|
||||
//try to find the context file in the filesystem
|
||||
if (fileName.startsWith("/"))
|
||||
res = getFileAsResource(fileName);
|
||||
if (res != null)
|
||||
return res;
|
||||
|
||||
//try to find it relative to 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, fileName);
|
||||
}
|
||||
if (res != null)
|
||||
return res;
|
||||
|
||||
//try to find it relative to an override location that has been specified
|
||||
if (bundleOverrideLocation != null)
|
||||
{
|
||||
try (Resource location = Resource.newResource(bundleOverrideLocation))
|
||||
{
|
||||
res = location.addPath(fileName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to find relative override location: {}", bundleOverrideLocation, e);
|
||||
}
|
||||
}
|
||||
if (res != null)
|
||||
return res;
|
||||
|
||||
//try to find it relative to the bundle in which it is being deployed
|
||||
if (containingBundle != null)
|
||||
{
|
||||
if (fileName.startsWith("./"))
|
||||
fileName = fileName.substring(1);
|
||||
|
||||
if (!fileName.startsWith("/"))
|
||||
fileName = "/" + fileName;
|
||||
|
||||
URL entry = _bundle.getEntry(fileName);
|
||||
if (entry != null)
|
||||
res = Resource.newResource(entry);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,553 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.Dictionary;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.internal.webapp.OSGiWebappClassLoader;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppClassLoader;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.resource.JarResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.service.packageadmin.PackageAdmin;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* AbstractWebAppProvider
|
||||
* <p>
|
||||
* Base class for Jetty DeploymentManager Providers that are capable of deploying a webapp,
|
||||
* either from a bundle or an OSGi service.
|
||||
*/
|
||||
public abstract class AbstractWebAppProvider extends AbstractLifeCycle implements AppProvider
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractWebAppProvider.class);
|
||||
|
||||
private boolean _parentLoaderPriority;
|
||||
|
||||
private String _defaultsDescriptor;
|
||||
|
||||
private boolean _extractWars = true; //See WebAppContext.extractWars
|
||||
|
||||
private String _tldBundles;
|
||||
|
||||
private DeploymentManager _deploymentManager;
|
||||
|
||||
private ServerInstanceWrapper _serverWrapper;
|
||||
|
||||
/**
|
||||
* OSGiApp
|
||||
*
|
||||
* Represents a deployable webapp.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
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));
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("Bundle location is {}, install location: {}", _bundle.getLocation(), bundleInstallLocation);
|
||||
}
|
||||
|
||||
URL url = null;
|
||||
Resource rootResource = Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(bundleInstallLocation.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;
|
||||
}
|
||||
|
||||
//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();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Webapp base using bundle install location: {}", url);
|
||||
}
|
||||
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();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Webapp base using absolute location: {}", url);
|
||||
}
|
||||
else if (bundleInstallLocation != null && bundleInstallLocation.isDirectory())
|
||||
{
|
||||
url = new File(bundleInstallLocation, _webAppPath).toURI().toURL();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Webapp base using path relative to bundle unpacked install location: {}", url);
|
||||
}
|
||||
else if (bundleInstallLocation != null)
|
||||
{
|
||||
Enumeration<URL> urls = BundleFileLocatorHelperFactory.getFactory().getHelper().findEntries(_bundle, _webAppPath);
|
||||
if (urls != null && urls.hasMoreElements())
|
||||
{
|
||||
url = urls.nextElement();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Webapp base using path relative to packed bundle location: {}", url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (url == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Unable to locate " + _webAppPath + " in " +
|
||||
(bundleInstallLocation != null ? bundleInstallLocation.getAbsolutePath() : "unlocated bundle '" + _bundle.getSymbolicName() + "'"));
|
||||
}
|
||||
|
||||
//Sets the location of the war file
|
||||
// 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());
|
||||
|
||||
//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-ee10.xml
|
||||
tmp = (String)_properties.get(OSGiWebappConstants.JETTY_DEFAULT_WEB_XML_PATH);
|
||||
if (tmp != null)
|
||||
{
|
||||
File defaultWebXml = getFile(tmp, bundleInstallLocation);
|
||||
if (defaultWebXml != null)
|
||||
{
|
||||
if (defaultWebXml.exists())
|
||||
_webApp.setDefaultsDescriptor(defaultWebXml.getAbsolutePath());
|
||||
else
|
||||
LOG.warn("{} does not exist", 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
|
||||
try
|
||||
{
|
||||
final Resource finalRootResource = rootResource;
|
||||
WebAppClassLoader.runWithServerClassAccess(() ->
|
||||
{
|
||||
applyMetaInfContextXml(finalRootResource, overrideBundleInstallLocation);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Error applying context xml");
|
||||
throw e;
|
||||
}
|
||||
|
||||
_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());
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("getPathsToRequiredBundles: bundle path={} uri={}", bs[0].getLocation(), f.toURI());
|
||||
}
|
||||
|
||||
return paths.toString();
|
||||
}
|
||||
|
||||
protected void applyMetaInfContextXml(Resource rootResource, String overrideBundleInstallLocation)
|
||||
throws Exception
|
||||
{
|
||||
if (_bundle == null)
|
||||
return;
|
||||
if (_webApp == null)
|
||||
return;
|
||||
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Context classloader = {}", cl);
|
||||
try
|
||||
{
|
||||
|
||||
Thread.currentThread().setContextClassLoader(_webApp.getClassLoader());
|
||||
|
||||
URI contextXmlUri = null;
|
||||
|
||||
//TODO replace this with getting the InputStream so we don't cache in URL
|
||||
//Try looking for a context xml file in META-INF with a specific name
|
||||
URL url = _bundle.getEntry("/META-INF/jetty-webapp-context.xml");
|
||||
if (url != null)
|
||||
{
|
||||
contextXmlUri = url.toURI();
|
||||
}
|
||||
|
||||
if (contextXmlUri == null)
|
||||
{
|
||||
//Didn't find specially named file, try looking for a property that names a context xml file to use
|
||||
if (_properties != null)
|
||||
{
|
||||
String tmp = (String)_properties.get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH);
|
||||
if (tmp != null)
|
||||
{
|
||||
String[] filenames = tmp.split("[,;]");
|
||||
if (filenames != null && filenames.length > 0)
|
||||
{
|
||||
String filename = filenames[0]; //should only be 1 filename in this usage
|
||||
String jettyHome = (String)getServerInstanceWrapper().getServer().getAttribute(OSGiServerConstants.JETTY_HOME);
|
||||
if (jettyHome == null)
|
||||
jettyHome = System.getProperty(OSGiServerConstants.JETTY_HOME);
|
||||
Resource res = findFile(filename, jettyHome, overrideBundleInstallLocation, _bundle);
|
||||
if (res != null)
|
||||
{
|
||||
contextXmlUri = res.getURI();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (contextXmlUri == null)
|
||||
return;
|
||||
|
||||
// Apply it just as the standard jetty ContextProvider would do
|
||||
LOG.info("Applying {} to {}", contextXmlUri, _webApp);
|
||||
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.newResource(contextXmlUri));
|
||||
WebAppClassLoader.runWithServerClassAccess(() ->
|
||||
{
|
||||
HashMap<String, String> properties = new HashMap<>();
|
||||
xmlConfiguration.getIdMap().put("Server", getDeploymentManager().getServer());
|
||||
properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString());
|
||||
properties.put(OSGiServerConstants.JETTY_HOME, (String)getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME));
|
||||
xmlConfiguration.getProperties().putAll(properties);
|
||||
xmlConfiguration.configure(_webApp);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
}
|
||||
}
|
||||
|
||||
private File getFile(String file, File bundleInstall)
|
||||
{
|
||||
if (file == null)
|
||||
return null;
|
||||
|
||||
if (file.startsWith("/") || file.startsWith("file:/")) //absolute location
|
||||
return new File(file);
|
||||
else
|
||||
{
|
||||
//relative location
|
||||
//try inside the bundle first
|
||||
File f = new File(bundleInstall, file);
|
||||
if (f.exists())
|
||||
return f;
|
||||
String jettyHome = (String)getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME);
|
||||
if (jettyHome != null)
|
||||
return new File(jettyHome, file);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void setServerInstanceWrapper(ServerInstanceWrapper wrapper)
|
||||
{
|
||||
_serverWrapper = wrapper;
|
||||
}
|
||||
|
||||
public ServerInstanceWrapper getServerInstanceWrapper()
|
||||
{
|
||||
return _serverWrapper;
|
||||
}
|
||||
|
||||
public DeploymentManager getDeploymentManager()
|
||||
{
|
||||
return _deploymentManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeploymentManager(DeploymentManager deploymentManager)
|
||||
{
|
||||
_deploymentManager = deploymentManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,257 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.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.ee10.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.Util;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.BundleEvent;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.osgi.util.tracker.BundleTracker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* BundleWebAppProvider
|
||||
* <p>
|
||||
* 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 = LoggerFactory.getLogger(AbstractWebAppProvider.class);
|
||||
|
||||
/**
|
||||
* Map of Bundle to App. Used when a Bundle contains a webapp.
|
||||
*/
|
||||
private Map<Bundle, App> _bundleMap = new HashMap<>();
|
||||
|
||||
private ServiceRegistration _serviceRegForBundles;
|
||||
|
||||
private WebAppTracker _webappTracker;
|
||||
|
||||
public class WebAppTracker extends BundleTracker
|
||||
{
|
||||
protected String _managedServerName;
|
||||
|
||||
public WebAppTracker(BundleContext bundleContext, String managedServerName)
|
||||
{
|
||||
super(bundleContext, Bundle.ACTIVE | Bundle.STOPPING, null);
|
||||
_managedServerName = managedServerName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object addingBundle(Bundle bundle, BundleEvent event)
|
||||
{
|
||||
try
|
||||
{
|
||||
String serverName = (String)bundle.getHeaders().get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
if ((StringUtil.isBlank(serverName) && _managedServerName.equals(OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME)) ||
|
||||
(!StringUtil.isBlank(serverName) && (serverName.equals(_managedServerName))))
|
||||
{
|
||||
if (bundleAdded(bundle))
|
||||
return bundle;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to add bundle {}", bundle, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removedBundle(Bundle bundle, BundleEvent event, Object object)
|
||||
{
|
||||
try
|
||||
{
|
||||
bundleRemoved(bundle);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to remove bundle {}", bundle, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BundleWebAppProvider(ServerInstanceWrapper wrapper)
|
||||
{
|
||||
super(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
_webappTracker = new WebAppTracker(FrameworkUtil.getBundle(this.getClass()).getBundleContext(), getServerInstanceWrapper().getManagedServerName());
|
||||
_webappTracker.open();
|
||||
//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<>();
|
||||
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
|
||||
{
|
||||
_webappTracker.close();
|
||||
|
||||
//unregister ourselves
|
||||
if (_serviceRegForBundles != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_serviceRegForBundles.unregister();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to unregister {}", _serviceRegForBundles, e);
|
||||
}
|
||||
}
|
||||
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
/**
|
||||
* A bundle has been added that could be a webapp
|
||||
*
|
||||
* @param bundle the bundle
|
||||
*/
|
||||
@Override
|
||||
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
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
Dictionary<String, String> headers = bundle.getHeaders();
|
||||
|
||||
//does the bundle have a OSGiWebappConstants.JETTY_WAR_FOLDER_PATH
|
||||
String resourcePath = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH, headers);
|
||||
if (resourcePath != null)
|
||||
{
|
||||
String base = resourcePath;
|
||||
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 = 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 the bundle
|
||||
* @return true if this was a webapp we had deployed, false otherwise
|
||||
*/
|
||||
@Override
|
||||
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 = StringUtil.replace(location, '\\', '/').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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,613 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.ee10.webapp.Configuration;
|
||||
import org.eclipse.jetty.ee10.webapp.Configurations;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppClassLoader;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.osgi.AbstractContextProvider;
|
||||
import org.eclipse.jetty.osgi.BundleContextProvider;
|
||||
import org.eclipse.jetty.osgi.BundleWebAppProvider;
|
||||
import org.eclipse.jetty.osgi.ContextFactory;
|
||||
import org.eclipse.jetty.osgi.OSGiApp;
|
||||
import org.eclipse.jetty.osgi.OSGiServerConstants;
|
||||
import org.eclipse.jetty.osgi.OSGiWebappConstants;
|
||||
import org.eclipse.jetty.osgi.util.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.osgi.util.FakeURLClassLoader;
|
||||
import org.eclipse.jetty.osgi.util.OSGiClassLoader;
|
||||
import org.eclipse.jetty.osgi.util.ServerClasspathContributor;
|
||||
import org.eclipse.jetty.osgi.util.Util;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
import org.eclipse.jetty.util.resource.URLResourceFactory;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
import org.osgi.util.tracker.ServiceTrackerCustomizer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* EE10Activator
|
||||
* <p>
|
||||
* Enable deployment of webapps/contexts to E10E
|
||||
*/
|
||||
public class EE10Activator implements BundleActivator
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(EE10Activator.class);
|
||||
|
||||
public static final String ENVIRONMENT = "ee10";
|
||||
|
||||
private static Collection<ServerClasspathContributor> __serverClasspathContributors = new ArrayList<>();
|
||||
|
||||
public static void registerServerClasspathContributor(ServerClasspathContributor contributor)
|
||||
{
|
||||
__serverClasspathContributors.add(contributor);
|
||||
}
|
||||
|
||||
public static void unregisterServerClasspathContributor(ServerClasspathContributor contributor)
|
||||
{
|
||||
__serverClasspathContributors.remove(contributor);
|
||||
}
|
||||
|
||||
public static Collection<ServerClasspathContributor> getServerClasspathContributors()
|
||||
{
|
||||
return __serverClasspathContributors;
|
||||
}
|
||||
|
||||
/**
|
||||
* ServerTracker
|
||||
*
|
||||
* Tracks appearance of Server instances as OSGi services, and then configures them
|
||||
* for deployment of EE10 contexts and webapps.
|
||||
*
|
||||
*/
|
||||
public static class ServerTracker implements ServiceTrackerCustomizer<Server, Object>
|
||||
{
|
||||
private Bundle _myBundle = null;
|
||||
|
||||
public ServerTracker(Bundle bundle)
|
||||
{
|
||||
_myBundle = bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object addingService(ServiceReference<Server> sr)
|
||||
{
|
||||
Bundle contributor = sr.getBundle();
|
||||
Server server = contributor.getBundleContext().getService(sr);
|
||||
//find bundles that should be on the container classpath and convert to URLs
|
||||
List<URL> contributedURLs = new ArrayList<>();
|
||||
List<Bundle> contributedBundles = new ArrayList<>();
|
||||
Collection<ServerClasspathContributor> serverClasspathContributors = getServerClasspathContributors();
|
||||
serverClasspathContributors.stream().forEach(c -> contributedBundles.addAll(c.getScannableBundles()));
|
||||
contributedBundles.stream().forEach(b -> contributedURLs.addAll(convertBundleToURL(b)));
|
||||
|
||||
if (!contributedURLs.isEmpty())
|
||||
{
|
||||
//There should already be a default set up by the JettyServerFactory
|
||||
ClassLoader serverClassLoader = (ClassLoader)server.getAttribute(OSGiServerConstants.SERVER_CLASSLOADER);
|
||||
if (serverClassLoader != null)
|
||||
{
|
||||
server.setAttribute(OSGiServerConstants.SERVER_CLASSLOADER,
|
||||
new FakeURLClassLoader(serverClassLoader, contributedURLs.toArray(new URL[contributedURLs.size()])));
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Server classloader for contexts = {}", server.getAttribute(OSGiServerConstants.SERVER_CLASSLOADER));
|
||||
}
|
||||
server.setAttribute(OSGiServerConstants.SERVER_CLASSPATH_BUNDLES, contributedBundles);
|
||||
}
|
||||
|
||||
Optional<DeploymentManager> deployer = getDeploymentManager(server);
|
||||
BundleWebAppProvider webAppProvider = null;
|
||||
BundleContextProvider contextProvider = null;
|
||||
|
||||
String containerScanBundlePattern = null;
|
||||
if (contributedBundles != null)
|
||||
{
|
||||
StringBuffer strbuff = new StringBuffer();
|
||||
contributedBundles.stream().forEach(b -> strbuff.append(b.getSymbolicName()).append("|"));
|
||||
|
||||
if (strbuff.length() > 0)
|
||||
containerScanBundlePattern = strbuff.toString().substring(0, strbuff.length() - 1);
|
||||
}
|
||||
|
||||
if (deployer.isPresent())
|
||||
{
|
||||
for (AppProvider provider : deployer.get().getAppProviders())
|
||||
{
|
||||
if (BundleContextProvider.class.isInstance(provider) && ENVIRONMENT.equalsIgnoreCase(provider.getEnvironmentName()))
|
||||
contextProvider = BundleContextProvider.class.cast(provider);
|
||||
if (BundleWebAppProvider.class.isInstance(provider) && ENVIRONMENT.equalsIgnoreCase(provider.getEnvironmentName()))
|
||||
webAppProvider = BundleWebAppProvider.class.cast(provider);
|
||||
}
|
||||
if (contextProvider == null)
|
||||
{
|
||||
contextProvider = new BundleContextProvider(ENVIRONMENT, server, new EE10ContextFactory(_myBundle));
|
||||
deployer.get().addAppProvider(contextProvider);
|
||||
}
|
||||
|
||||
if (webAppProvider == null)
|
||||
{
|
||||
webAppProvider = new BundleWebAppProvider(ENVIRONMENT, server, new EE10WebAppFactory(_myBundle));
|
||||
deployer.get().addAppProvider(webAppProvider);
|
||||
}
|
||||
|
||||
//ensure the providers are configured with the extra bundles that must be scanned from the container classpath
|
||||
if (containerScanBundlePattern != null)
|
||||
{
|
||||
contextProvider.getProperties().put(OSGiMetaInfConfiguration.CONTAINER_BUNDLE_PATTERN, containerScanBundlePattern);
|
||||
webAppProvider.getProperties().put(OSGiMetaInfConfiguration.CONTAINER_BUNDLE_PATTERN, containerScanBundlePattern);
|
||||
}
|
||||
}
|
||||
else
|
||||
LOG.info("No DeploymentManager for Server {}", server);
|
||||
|
||||
try
|
||||
{
|
||||
if (!server.isStarted())
|
||||
server.start();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Failed to start server {}", server);
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifiedService(ServiceReference<Server> reference, Object service)
|
||||
{
|
||||
removedService(reference, service);
|
||||
addingService(reference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removedService(ServiceReference<Server> reference, Object service)
|
||||
{
|
||||
}
|
||||
|
||||
private Optional<DeploymentManager> getDeploymentManager(Server server)
|
||||
{
|
||||
Collection<DeploymentManager> deployers = server.getBeans(DeploymentManager.class);
|
||||
return deployers.stream().findFirst();
|
||||
}
|
||||
|
||||
private List<URL> convertBundleToURL(Bundle bundle)
|
||||
{
|
||||
List<URL> urls = new ArrayList<>();
|
||||
try
|
||||
{
|
||||
File file = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bundle);
|
||||
|
||||
if (file.isDirectory())
|
||||
{
|
||||
for (File f : file.listFiles())
|
||||
{
|
||||
if (FileID.isJavaArchive(f.getName()) && f.isFile())
|
||||
{
|
||||
urls.add(f.toURI().toURL());
|
||||
}
|
||||
else if (f.isDirectory() && f.getName().equals("lib"))
|
||||
{
|
||||
for (File f2 : file.listFiles())
|
||||
{
|
||||
if (FileID.isJavaArchive(f2.getName()) && f2.isFile())
|
||||
{
|
||||
urls.add(f2.toURI().toURL());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
urls.add(file.toURI().toURL());
|
||||
}
|
||||
else
|
||||
{
|
||||
urls.add(file.toURI().toURL());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to convert bundle {} to url", bundle, e);
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
}
|
||||
|
||||
public static class EE10ContextFactory implements ContextFactory
|
||||
{
|
||||
private Bundle _myBundle;
|
||||
|
||||
public EE10ContextFactory(Bundle bundle)
|
||||
{
|
||||
_myBundle = bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextHandler createContextHandler(AbstractContextProvider provider, App app)
|
||||
throws Exception
|
||||
{
|
||||
OSGiApp osgiApp = OSGiApp.class.cast(app);
|
||||
String jettyHome = (String)app.getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME);
|
||||
Path jettyHomePath = (StringUtil.isBlank(jettyHome) ? null : Paths.get(jettyHome));
|
||||
|
||||
ContextHandler contextHandler = new ContextHandler();
|
||||
|
||||
//Make base resource that of the bundle
|
||||
contextHandler.setBaseResource(osgiApp.getBundleResource());
|
||||
|
||||
// provides access to core classes
|
||||
ClassLoader coreLoader = (ClassLoader)osgiApp.getDeploymentManager().getServer().getAttribute(OSGiServerConstants.SERVER_CLASSLOADER);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Core classloader = {}", coreLoader.getClass());
|
||||
|
||||
//provide access to all ee10 classes
|
||||
ClassLoader environmentLoader = new OSGiClassLoader(coreLoader, _myBundle);
|
||||
|
||||
//Use a classloader that knows about the common jetty parent loader, and also the bundle
|
||||
OSGiClassLoader classLoader = new OSGiClassLoader(environmentLoader, osgiApp.getBundle());
|
||||
contextHandler.setClassLoader(classLoader);
|
||||
|
||||
//Apply any context xml file
|
||||
String tmp = osgiApp.getProperties().get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH);
|
||||
final URI contextXmlURI = Util.resolvePathAsLocalizedURI(tmp, osgiApp.getBundle(), jettyHomePath);
|
||||
|
||||
if (contextXmlURI != null)
|
||||
{
|
||||
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
|
||||
try
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(contextHandler.getClassLoader());
|
||||
WebAppClassLoader.runWithServerClassAccess(() ->
|
||||
{
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(ResourceFactory.of(contextHandler).newResource(contextXmlURI));
|
||||
WebAppClassLoader.runWithServerClassAccess(() ->
|
||||
{
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
xmlConfiguration.getIdMap().put("Server", osgiApp.getDeploymentManager().getServer());
|
||||
properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, osgiApp.getPath().toUri().toString());
|
||||
properties.put(OSGiServerConstants.JETTY_HOME, (String)osgiApp.getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME));
|
||||
xmlConfiguration.getProperties().putAll(properties);
|
||||
xmlConfiguration.configure(contextHandler);
|
||||
return null;
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Error applying context xml", e);
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(oldLoader);
|
||||
}
|
||||
}
|
||||
|
||||
//osgi Enterprise Spec r4 p.427
|
||||
contextHandler.setAttribute(OSGiWebappConstants.OSGI_BUNDLECONTEXT, osgiApp.getBundle().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);
|
||||
|
||||
return contextHandler;
|
||||
}
|
||||
}
|
||||
|
||||
public static class EE10WebAppFactory implements ContextFactory
|
||||
{
|
||||
private Bundle _myBundle;
|
||||
|
||||
public EE10WebAppFactory(Bundle bundle)
|
||||
{
|
||||
_myBundle = bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextHandler createContextHandler(AbstractContextProvider provider, App app)
|
||||
throws Exception
|
||||
{
|
||||
OSGiApp osgiApp = OSGiApp.class.cast(app);
|
||||
String jettyHome = (String)app.getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME);
|
||||
Path jettyHomePath = (StringUtil.isBlank(jettyHome) ? null : Paths.get(jettyHome));
|
||||
|
||||
WebAppContext webApp = new WebAppContext();
|
||||
|
||||
//Apply defaults from the deployer providers
|
||||
webApp.initializeDefaults(provider.getProperties());
|
||||
|
||||
// provides access to core classes
|
||||
ClassLoader coreLoader = (ClassLoader)osgiApp.getDeploymentManager().getServer().getAttribute(OSGiServerConstants.SERVER_CLASSLOADER);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Core classloader = {}", coreLoader);
|
||||
|
||||
//provide access to all ee10 classes
|
||||
ClassLoader environmentLoader = new OSGiClassLoader(coreLoader, _myBundle);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Environment classloader = {}", environmentLoader);
|
||||
|
||||
//Ensure Configurations.getKnown is called with a classloader that can see all of the ee10 and core classes
|
||||
|
||||
ClassLoader old = Thread.currentThread().getContextClassLoader();
|
||||
try
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(environmentLoader);
|
||||
WebAppClassLoader.runWithServerClassAccess(() ->
|
||||
{
|
||||
Configurations.getKnown();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(old);
|
||||
}
|
||||
|
||||
webApp.setConfigurations(Configurations.getKnown().stream()
|
||||
.filter(c -> c.isEnabledByDefault())
|
||||
.toArray(Configuration[]::new));
|
||||
|
||||
//Make a webapp classloader
|
||||
OSGiWebappClassLoader webAppLoader = new OSGiWebappClassLoader(environmentLoader, webApp, osgiApp.getBundle());
|
||||
|
||||
//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)osgiApp.getProperties().get(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
|
||||
|
||||
List<Path> pathsToTldBundles = Util.getPathsToBundlesBySymbolicNames(requireTldBundles, osgiApp.getBundle().getBundleContext());
|
||||
for (Path p : pathsToTldBundles)
|
||||
webAppLoader.addClassPath(p.toUri().toString());
|
||||
|
||||
//Set up configuration from manifest headers
|
||||
//extra classpath
|
||||
String extraClasspath = osgiApp.getProperties().get(OSGiWebappConstants.JETTY_EXTRA_CLASSPATH);
|
||||
if (extraClasspath != null)
|
||||
webApp.setExtraClasspath(extraClasspath);
|
||||
|
||||
webApp.setClassLoader(webAppLoader);
|
||||
|
||||
//Take care of extra provider properties
|
||||
webApp.setAttribute(OSGiMetaInfConfiguration.CONTAINER_BUNDLE_PATTERN, provider.getProperties().get(OSGiMetaInfConfiguration.CONTAINER_BUNDLE_PATTERN));
|
||||
|
||||
//TODO needed?
|
||||
webApp.setAttribute(OSGiWebappConstants.REQUIRE_TLD_BUNDLE, requireTldBundles);
|
||||
|
||||
//Set up some attributes
|
||||
// rfc66
|
||||
webApp.setAttribute(OSGiWebappConstants.RFC66_OSGI_BUNDLE_CONTEXT, osgiApp.getBundle().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(), osgiApp.getBundle().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, osgiApp.getBundle());
|
||||
|
||||
|
||||
// apply any META-INF/context.xml file that is found to configure
|
||||
// the webapp first
|
||||
//First try looking for one in /META-INF
|
||||
URI tmpUri = null;
|
||||
|
||||
URL contextXmlURL = Util.getLocalizedEntry("/META-INF/jetty-webapp-context.xml", osgiApp.getBundle());
|
||||
if (contextXmlURL != null)
|
||||
tmpUri = contextXmlURL.toURI();
|
||||
|
||||
//Then look in the property OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH and apply the first one
|
||||
if (contextXmlURL == null)
|
||||
{
|
||||
String tmp = osgiApp.getProperties().get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH);
|
||||
if (tmp != null)
|
||||
{
|
||||
String[] filenames = tmp.split("[,;]");
|
||||
tmpUri = Util.resolvePathAsLocalizedURI(filenames[0], osgiApp.getBundle(), jettyHomePath);
|
||||
}
|
||||
}
|
||||
|
||||
//apply a context xml if there is one
|
||||
if (tmpUri != null)
|
||||
{
|
||||
final URI contextXmlUri = tmpUri;
|
||||
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
|
||||
try
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(webApp.getClassLoader());
|
||||
WebAppClassLoader.runWithServerClassAccess(() ->
|
||||
{
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(ResourceFactory.of(webApp).newResource(contextXmlUri));
|
||||
WebAppClassLoader.runWithServerClassAccess(() ->
|
||||
{
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
xmlConfiguration.getIdMap().put("Server", osgiApp.getDeploymentManager().getServer());
|
||||
properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, osgiApp.getPath().toUri().toString());
|
||||
properties.put(OSGiServerConstants.JETTY_HOME, (String)osgiApp.getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME));
|
||||
xmlConfiguration.getProperties().putAll(properties);
|
||||
xmlConfiguration.configure(webApp);
|
||||
return null;
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Error applying context xml", e);
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(oldLoader);
|
||||
}
|
||||
}
|
||||
|
||||
//ensure the context path is set
|
||||
webApp.setContextPath(osgiApp.getContextPath());
|
||||
|
||||
//osgi Enterprise Spec r4 p.427
|
||||
webApp.setAttribute(OSGiWebappConstants.OSGI_BUNDLECONTEXT, osgiApp.getBundle().getBundleContext());
|
||||
|
||||
//Indicate the webapp has been deployed, so that we don't try and redeploy again
|
||||
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);
|
||||
|
||||
|
||||
Path bundlePath = osgiApp.getPath();
|
||||
|
||||
Resource bundleResource = osgiApp.getBundleResource();
|
||||
|
||||
String pathToResourceBase = osgiApp.getPathToResourceBase();
|
||||
|
||||
//if the path wasn't set or it was ., then it is the root of the bundle's installed location
|
||||
if (StringUtil.isBlank(pathToResourceBase) || ".".equals(pathToResourceBase))
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Webapp base using bundle install location: {}", bundleResource);
|
||||
webApp.setWarResource(bundleResource);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pathToResourceBase.startsWith("/") || pathToResourceBase.startsWith("file:"))
|
||||
{
|
||||
//The baseResource is outside of the bundle
|
||||
Path p = Paths.get(pathToResourceBase);
|
||||
webApp.setWar(p.toUri().toString());
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Webapp base using absolute location: {}", p);
|
||||
}
|
||||
else
|
||||
{
|
||||
//The baseResource is relative to the root of the bundle
|
||||
Resource r = bundleResource.resolve(pathToResourceBase);
|
||||
webApp.setWarResource(r);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Webapp base using path relative to bundle unpacked install location: {}", r);
|
||||
}
|
||||
}
|
||||
|
||||
//web.xml
|
||||
String tmp = osgiApp.getProperties().get(OSGiWebappConstants.JETTY_WEB_XML_PATH);
|
||||
if (!StringUtil.isBlank(tmp))
|
||||
{
|
||||
URI webXml = Util.resolvePathAsLocalizedURI(tmp, osgiApp.getBundle(), jettyHomePath);
|
||||
if (webXml != null)
|
||||
webApp.setDescriptor(webXml.toString());
|
||||
}
|
||||
|
||||
// webdefault-ee10.xml
|
||||
tmp = osgiApp.getProperties().get(OSGiWebappConstants.JETTY_DEFAULT_WEB_XML_PATH);
|
||||
if (tmp != null)
|
||||
{
|
||||
URI defaultWebXml = Util.resolvePathAsLocalizedURI(tmp, osgiApp.getBundle(), jettyHomePath);
|
||||
if (defaultWebXml != null)
|
||||
{
|
||||
webApp.setDefaultsDescriptor(defaultWebXml.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return webApp;
|
||||
}
|
||||
}
|
||||
|
||||
private PackageAdminServiceTracker _packageAdminServiceTracker;
|
||||
private ServiceTracker<Server, Object> _tracker;
|
||||
|
||||
/**
|
||||
* Track jetty Server instances and add ability to deploy EE10 contexts/webapps
|
||||
*
|
||||
* @param context the bundle context
|
||||
*/
|
||||
@Override
|
||||
public void start(final BundleContext context) throws Exception
|
||||
{
|
||||
// track other bundles and fragments attached to this bundle that we
|
||||
// should activate.
|
||||
_packageAdminServiceTracker = new PackageAdminServiceTracker(context);
|
||||
|
||||
//track jetty Server instances
|
||||
_tracker = new ServiceTracker<Server, Object>(context, context.createFilter("(objectclass=" + Server.class.getName() + ")"), new ServerTracker(context.getBundle()));
|
||||
_tracker.open();
|
||||
|
||||
//register for bundleresource: url resource handling
|
||||
ResourceFactory.registerResourceFactory("bundleresource", new URLResourceFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the activator.
|
||||
*
|
||||
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
|
||||
*/
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception
|
||||
{
|
||||
if (_tracker != null)
|
||||
{
|
||||
_tracker.close();
|
||||
_tracker = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
|
||||
import org.eclipse.jetty.ee10.osgi.boot.internal.serverfactory.DefaultJettyAtJettyHomeHelper;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.internal.serverfactory.JettyServerServiceTracker;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.internal.PackageAdminServiceTracker;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* JettyBootstrapActivator
|
||||
* <p>
|
||||
* Bootstrap jetty and publish a default Server instance as an OSGi service.
|
||||
* <p>
|
||||
* Listen for other Server instances to be published as services and support them as deployment targets.
|
||||
* <p>
|
||||
* Listen for Bundles to be activated, and deploy those that represent webapps/ContextHandlers to one of the known Server instances.
|
||||
*/
|
||||
public class JettyBootstrapActivator implements BundleActivator
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JettyBootstrapActivator.class);
|
||||
|
||||
private static JettyBootstrapActivator INSTANCE = null;
|
||||
|
||||
public static JettyBootstrapActivator getInstance()
|
||||
{
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private ServiceRegistration _registeredServer;
|
||||
|
||||
private PackageAdminServiceTracker _packageAdminServiceTracker;
|
||||
|
||||
private ServiceTracker _jettyServerServiceTracker;
|
||||
|
||||
/**
|
||||
* Setup a new jetty Server, registers it as a service. Setup the Service
|
||||
* tracker for the jetty ContextHandlers that are in charge of deploying the
|
||||
* webapps. Setup the BundleListener that supports the extender pattern for
|
||||
* the jetty ContextHandler.
|
||||
*
|
||||
* @param context the bundle context
|
||||
*/
|
||||
@Override
|
||||
public void start(final BundleContext context) throws Exception
|
||||
{
|
||||
ServiceReference[] references = context.getAllServiceReferences("org.eclipse.jetty.http.HttpFieldPreEncoder", null);
|
||||
|
||||
if (references == null || references.length == 0)
|
||||
LOG.warn("OSGi support for java.util.ServiceLoader may not be present. You may experience runtime errors.");
|
||||
|
||||
INSTANCE = this;
|
||||
|
||||
// track other bundles and fragments attached to this bundle that we
|
||||
// should activate.
|
||||
_packageAdminServiceTracker = new PackageAdminServiceTracker(context);
|
||||
|
||||
// track jetty Server instances that we should support as deployment targets
|
||||
_jettyServerServiceTracker = new ServiceTracker(context, context.createFilter("(objectclass=" + Server.class.getName() + ")"), new JettyServerServiceTracker());
|
||||
_jettyServerServiceTracker.open();
|
||||
|
||||
// Create a default jetty instance right now.
|
||||
DefaultJettyAtJettyHomeHelper.startJettyAtJettyHome(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the activator.
|
||||
*
|
||||
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
|
||||
*/
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_jettyServerServiceTracker != null)
|
||||
{
|
||||
_jettyServerServiceTracker.close();
|
||||
_jettyServerServiceTracker = null;
|
||||
}
|
||||
if (_packageAdminServiceTracker != null)
|
||||
{
|
||||
_packageAdminServiceTracker.stop();
|
||||
context.removeServiceListener(_packageAdminServiceTracker);
|
||||
_packageAdminServiceTracker = null;
|
||||
}
|
||||
if (_registeredServer != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_registeredServer.unregister();
|
||||
}
|
||||
catch (IllegalArgumentException ill)
|
||||
{
|
||||
// already unregistered.
|
||||
}
|
||||
finally
|
||||
{
|
||||
_registeredServer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
INSTANCE = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.bindings.StandardDeployer;
|
||||
import org.eclipse.jetty.deploy.graph.Node;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.EventSender;
|
||||
|
||||
/**
|
||||
* OSGiDeployer
|
||||
*
|
||||
* Extension of standard Jetty deployer that emits OSGi EventAdmin
|
||||
* events whenever a webapp is deployed into OSGi via Jetty.
|
||||
*/
|
||||
public class OSGiDeployer extends StandardDeployer
|
||||
{
|
||||
|
||||
private ServerInstanceWrapper _server;
|
||||
|
||||
public OSGiDeployer(ServerInstanceWrapper server)
|
||||
{
|
||||
_server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processBinding(Node node, App app) throws Exception
|
||||
{
|
||||
//TODO how to NOT send this event if its not a webapp:
|
||||
//OSGi Enterprise Spec only wants an event sent if its a webapp bundle (ie not a ContextHandler)
|
||||
if (!(app instanceof AbstractOSGiApp))
|
||||
{
|
||||
doProcessBinding(node, app);
|
||||
}
|
||||
else
|
||||
{
|
||||
EventSender.getInstance().send(EventSender.DEPLOYING_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath());
|
||||
try
|
||||
{
|
||||
doProcessBinding(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void doProcessBinding(Node node, App app) throws Exception
|
||||
{
|
||||
ClassLoader old = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(_server.getParentClassLoaderForWebapps());
|
||||
try
|
||||
{
|
||||
super.processBinding(node, app);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(old);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,34 +27,34 @@ import java.util.StringTokenizer;
|
|||
import java.util.TreeMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.Util;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.internal.PackageAdminServiceTracker;
|
||||
import org.eclipse.jetty.ee10.webapp.Configuration;
|
||||
import org.eclipse.jetty.ee10.webapp.MetaInfConfiguration;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.ee10.webapp.WebInfConfiguration;
|
||||
import org.eclipse.jetty.osgi.OSGiWebappConstants;
|
||||
import org.eclipse.jetty.osgi.util.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.osgi.util.Util;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* OSGiWebInfConfiguration
|
||||
* OSGiMetaInfConfiguration
|
||||
*
|
||||
* Handle adding resources found in bundle fragments, and add them into the
|
||||
* Handle adding resources found in bundles.
|
||||
*/
|
||||
public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WebInfConfiguration.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(OSGiMetaInfConfiguration.class);
|
||||
|
||||
/**
|
||||
* Comma separated list of symbolic names of bundles that contain tlds that should be considered
|
||||
* as on the container classpath
|
||||
*/
|
||||
public static final String SYS_PROP_TLD_BUNDLES = "org.eclipse.jetty.ee10.osgi.tldbundles";
|
||||
public static final String SYS_PROP_TLD_BUNDLES = "org.eclipse.jetty.osgi.tldbundles";
|
||||
/**
|
||||
* Regex of symbolic names of bundles that should be considered to be on the container classpath
|
||||
*/
|
||||
|
@ -108,13 +108,15 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
|||
names.add(tokenizer.nextToken());
|
||||
}
|
||||
}
|
||||
HashSet<Resource> matchingResources = new HashSet<Resource>();
|
||||
|
||||
HashSet<Resource> matchingResources = new HashSet<>();
|
||||
if (!names.isEmpty() || pattern != null)
|
||||
{
|
||||
Bundle[] bundles = FrameworkUtil.getBundle(OSGiMetaInfConfiguration.class).getBundleContext().getBundles();
|
||||
|
||||
for (Bundle bundle : bundles)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Checking bundle {}:{}", bundle.getBundleId(), bundle.getSymbolicName());
|
||||
if (pattern != null)
|
||||
{
|
||||
|
@ -122,14 +124,14 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
|||
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));
|
||||
matchingResources.addAll(getBundleAsResource(ResourceFactory.of(context), 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));
|
||||
matchingResources.addAll(getBundleAsResource(ResourceFactory.of(context), bundle));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,6 +170,7 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
|||
Bundle[] bundles = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles((Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE));
|
||||
if (bundles != null && bundles.length > 0)
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<Bundle> fragsAndReqsBundles = (Set<Bundle>)context.getAttribute(FRAGMENT_AND_REQUIRED_BUNDLES);
|
||||
if (fragsAndReqsBundles == null)
|
||||
{
|
||||
|
@ -175,6 +178,7 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
|||
context.setAttribute(FRAGMENT_AND_REQUIRED_BUNDLES, fragsAndReqsBundles);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<Resource> fragsAndReqsResources = (Set<Resource>)context.getAttribute(FRAGMENT_AND_REQUIRED_RESOURCES);
|
||||
if (fragsAndReqsResources == null)
|
||||
{
|
||||
|
@ -191,7 +195,7 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
|||
//add to context attribute storing associated fragments and required bundles
|
||||
fragsAndReqsBundles.add(b);
|
||||
File f = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(b);
|
||||
Resource r = Resource.newResource(f.toURI());
|
||||
Resource r = ResourceFactory.of(context).newResource(f.toURI());
|
||||
//add to convenience context attribute storing fragments and required bundles as Resources
|
||||
fragsAndReqsResources.add(r);
|
||||
mergedResources.add(r);
|
||||
|
@ -217,6 +221,7 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
|||
Bundle bundle = (Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
|
||||
if (bundle != null)
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<Bundle> fragments = (Set<Bundle>)context.getAttribute(FRAGMENT_AND_REQUIRED_BUNDLES);
|
||||
if (fragments != null && !fragments.isEmpty())
|
||||
{
|
||||
|
@ -236,14 +241,15 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
|||
for (Bundle frag : fragments)
|
||||
{
|
||||
String path = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_FRAGMENT_RESOURCE_PATH, frag.getHeaders());
|
||||
convertFragmentPathToResource(path, frag, appendedResourcesPath);
|
||||
convertFragmentPathToResource(ResourceFactory.of(context), path, frag, appendedResourcesPath);
|
||||
path = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_PREPEND_FRAGMENT_RESOURCE_PATH, frag.getHeaders());
|
||||
convertFragmentPathToResource(path, frag, prependedResourcesPath);
|
||||
convertFragmentPathToResource(ResourceFactory.of(context), path, frag, prependedResourcesPath);
|
||||
}
|
||||
if (!appendedResourcesPath.isEmpty())
|
||||
{
|
||||
LinkedHashSet<Resource> resources = new LinkedHashSet<Resource>();
|
||||
LinkedHashSet<Resource> resources = new LinkedHashSet<>();
|
||||
//Add in any existing setting of extra resource dirs
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<Resource> resourceDirs = (Set<Resource>)context.getAttribute(MetaInfConfiguration.RESOURCE_DIRS);
|
||||
if (resourceDirs != null && !resourceDirs.isEmpty())
|
||||
resources.addAll(resourceDirs);
|
||||
|
@ -263,8 +269,7 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
|||
Resource[] resources = new Resource[1 + prependedResourcesPath.size()];
|
||||
System.arraycopy(prependedResourcesPath.values().toArray(new Resource[prependedResourcesPath.size()]), 0, resources, 0, prependedResourcesPath.size());
|
||||
resources[resources.length - 1] = context.getBaseResource();
|
||||
|
||||
context.setBaseResource(Resource.of(resources));
|
||||
context.setBaseResource(ResourceFactory.combine(resources));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -272,10 +277,10 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
|||
* 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)
|
||||
private List<Resource> getBundleAsResource(ResourceFactory resourceFactory, Bundle bundle)
|
||||
throws Exception
|
||||
{
|
||||
List<Resource> resources = new ArrayList<Resource>();
|
||||
List<Resource> resources = new ArrayList<>();
|
||||
|
||||
File file = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bundle);
|
||||
if (file.isDirectory())
|
||||
|
@ -284,7 +289,7 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
|||
{
|
||||
if (FileID.isJavaArchive(f.getName()) && f.isFile())
|
||||
{
|
||||
resources.add(Resource.newResource(f));
|
||||
resources.add(resourceFactory.newResource(f.toPath()));
|
||||
}
|
||||
else if (f.isDirectory() && f.getName().equals("lib"))
|
||||
{
|
||||
|
@ -292,16 +297,16 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
|||
{
|
||||
if (FileID.isJavaArchive(f2.getName()) && f2.isFile())
|
||||
{
|
||||
resources.add(Resource.newResource(f));
|
||||
resources.add(resourceFactory.newResource(f.toPath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
resources.add(Resource.newResource(file)); //TODO really???
|
||||
resources.add(resourceFactory.newResource(file.toPath())); //TODO really???
|
||||
}
|
||||
else
|
||||
{
|
||||
resources.add(Resource.newResource(file));
|
||||
resources.add(resourceFactory.newResource(file.toPath()));
|
||||
}
|
||||
|
||||
return resources;
|
||||
|
@ -310,7 +315,7 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
|||
/**
|
||||
* Convert a path inside a fragment into a Resource
|
||||
*/
|
||||
private void convertFragmentPathToResource(String resourcePath, Bundle fragment, Map<String, Resource> resourceMap)
|
||||
private void convertFragmentPathToResource(ResourceFactory resourceFactory, String resourcePath, Bundle fragment, Map<String, Resource> resourceMap)
|
||||
throws Exception
|
||||
{
|
||||
if (resourcePath == null)
|
||||
|
@ -333,6 +338,6 @@ public class OSGiMetaInfConfiguration extends MetaInfConfiguration
|
|||
{
|
||||
uri = new URI(url.toString().replaceAll(" ", "%20"));
|
||||
}
|
||||
resourceMap.put(key + ";" + fragment.getSymbolicName(), Resource.newResource(uri));
|
||||
resourceMap.put(key + ";" + fragment.getSymbolicName(), resourceFactory.newResource(uri));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
|
||||
/**
|
||||
* OSGiServerConstants
|
||||
*
|
||||
* Name of the properties that configure a jetty Server OSGi service.
|
||||
*/
|
||||
public class OSGiServerConstants
|
||||
{
|
||||
/**
|
||||
* Usual system property used as the hostname for a typical jetty
|
||||
* configuration.
|
||||
*/
|
||||
public static final String JETTY_HOME = "jetty.home";
|
||||
public static final String JETTY_BASE = "jetty.base";
|
||||
|
||||
/**
|
||||
* 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.http.host";
|
||||
|
||||
/**
|
||||
* Usual system property used as the port for http for a typical jetty
|
||||
* configuration.
|
||||
*/
|
||||
public static final String JETTY_PORT = "jetty.http.port";
|
||||
|
||||
/**
|
||||
* Usual system property used as the port for https for a typical jetty
|
||||
* configuration.
|
||||
*/
|
||||
public static final String JETTY_PORT_SSL = "jetty.ssl.port";
|
||||
|
||||
//for managed jetty instances, name of the configuration parameters
|
||||
/**
|
||||
* PID of the jetty servers's ManagedFactory
|
||||
*/
|
||||
public static final String MANAGED_JETTY_SERVER_FACTORY_PID = "org.eclipse.jetty.ee10.osgi.boot.managedserverfactory";
|
||||
|
||||
/**
|
||||
* The associated value of that configuration parameter is the name under which this
|
||||
* instance of the jetty server is tracked.
|
||||
* When a ContextHandler is deployed and it specifies the managedServerName property, it is deployed
|
||||
* on the corresponding jetty managed server or it throws an exception: jetty server not available.
|
||||
*/
|
||||
public static final String MANAGED_JETTY_SERVER_NAME = "managedServerName";
|
||||
/**
|
||||
* Name of the 'default' jetty server instance.
|
||||
* Usually the first one to be created.
|
||||
*/
|
||||
public static final String MANAGED_JETTY_SERVER_DEFAULT_NAME = "defaultJettyServer";
|
||||
|
||||
/**
|
||||
* List of URLs to the jetty.xml files that configure th server.
|
||||
*/
|
||||
public static final String MANAGED_JETTY_XML_CONFIG_URLS = "jetty.etc.config.urls";
|
||||
|
||||
/**
|
||||
* List of URLs to the folders where the legacy J2EE shared libraries are stored aka lib/ext, lib/jsp etc.
|
||||
*/
|
||||
public static final String MANAGED_JETTY_SHARED_LIB_FOLDER_URLS = "managedJettySharedLibFolderUrls";
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.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.ee10.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.EventSender;
|
||||
|
||||
/**
|
||||
* OSGiUndeployer
|
||||
*
|
||||
* Extension of the Jetty Undeployer which emits OSGi EventAdmin events
|
||||
* whenever a webapp is undeployed from Jetty.
|
||||
*/
|
||||
public class OSGiUndeployer extends StandardUndeployer
|
||||
{
|
||||
private ServerInstanceWrapper _server;
|
||||
|
||||
public OSGiUndeployer(ServerInstanceWrapper server)
|
||||
{
|
||||
_server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processBinding(Node node, App app) throws Exception
|
||||
{
|
||||
EventSender.getInstance().send(EventSender.UNDEPLOYING_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath());
|
||||
ClassLoader old = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(_server.getParentClassLoaderForWebapps());
|
||||
try
|
||||
{
|
||||
super.processBinding(node, app);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(old);
|
||||
}
|
||||
EventSender.getInstance().send(EventSender.UNDEPLOYED_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath());
|
||||
((AbstractOSGiApp)app).deregisterAsOSGiService();
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
|
||||
import org.eclipse.jetty.ee10.webapp.Configuration;
|
||||
import org.eclipse.jetty.ee10.webapp.WebInfConfiguration;
|
||||
|
||||
/**
|
||||
* OSGiWebInfConfiguration
|
||||
*
|
||||
* Handle adding resources found in bundle fragments, and add them into the
|
||||
*/
|
||||
public class OSGiWebInfConfiguration extends WebInfConfiguration
|
||||
{
|
||||
@Override
|
||||
public Class<? extends Configuration> replaces()
|
||||
{
|
||||
return WebInfConfiguration.class;
|
||||
}
|
||||
}
|
|
@ -11,24 +11,15 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.internal.webapp;
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.BundleClassLoaderHelperFactory;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppClassLoader;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.osgi.util.BundleClassLoaderHelperFactory;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleReference;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -42,30 +33,8 @@ import org.slf4j.LoggerFactory;
|
|||
*/
|
||||
public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleReference
|
||||
{
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(OSGiWebappClassLoader.class.getName());
|
||||
|
||||
/**
|
||||
* when a logging framework is setup in the osgi classloaders, it can access
|
||||
* this and register the classes that must not be found in the jar.
|
||||
*/
|
||||
public static final Set<String> JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED = new HashSet<>();
|
||||
|
||||
public static void addClassThatIdentifiesAJarThatMustBeRejected(Class<?> zclass)
|
||||
{
|
||||
JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED.add(TypeUtil.toClassReference(zclass.getName()));
|
||||
}
|
||||
|
||||
public static void addClassThatIdentifiesAJarThatMustBeRejected(String zclassName)
|
||||
{
|
||||
JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED.add(TypeUtil.toClassReference(zclassName));
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
addClassThatIdentifiesAJarThatMustBeRejected(HttpServlet.class);
|
||||
}
|
||||
|
||||
private ClassLoader _osgiBundleClassLoader;
|
||||
|
||||
private Bundle _contributor;
|
||||
|
@ -171,91 +140,4 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<URL> toList(Enumeration<URL> e, Enumeration<URL> e2)
|
||||
{
|
||||
List<URL> list = new ArrayList<>();
|
||||
while (e != null && e.hasMoreElements())
|
||||
{
|
||||
list.add(e.nextElement());
|
||||
}
|
||||
while (e2 != null && e2.hasMoreElements())
|
||||
{
|
||||
list.add(e2.nextElement());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the classpath ourselves to be able to filter things. This is a
|
||||
* derivative work of the super class
|
||||
*/
|
||||
@Override
|
||||
public void addClassPath(String classPath) throws IOException
|
||||
{
|
||||
for (Resource resource : Resource.fromList(classPath, false, (path) -> getContext().newResource(path)))
|
||||
{
|
||||
File file = resource.getFile();
|
||||
if (file != null && isAcceptableLibrary(file, JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED))
|
||||
{
|
||||
super.addClassPath(resource);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.info("Did not add {} to the classloader of the webapp {}", resource, getContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the lib should be included in the webapp classloader.
|
||||
*/
|
||||
private boolean isAcceptableLibrary(File file, Set<String> pathToClassFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (file.isDirectory())
|
||||
{
|
||||
for (String criteria : pathToClassFiles)
|
||||
{
|
||||
if (new File(file, criteria).exists())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JarFile jar = null;
|
||||
try
|
||||
{
|
||||
jar = new JarFile(file);
|
||||
for (String criteria : pathToClassFiles)
|
||||
{
|
||||
if (jar.getEntry(criteria) != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (jar != null)
|
||||
try
|
||||
{
|
||||
jar.close();
|
||||
}
|
||||
catch (IOException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// nevermind. just trying our best
|
||||
LOG.trace("IGNORED", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
|
||||
/**
|
||||
* OSGiWebappConstants
|
||||
*
|
||||
*
|
||||
* Constants (MANIFEST headers, service properties etc) associated with deploying
|
||||
* webapps into OSGi via Jetty.
|
||||
*/
|
||||
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";
|
||||
|
||||
/**
|
||||
* Name of the header that defines the context path for the embedded webapp.
|
||||
*/
|
||||
public static final String RFC66_WEB_CONTEXTPATH = "Web-ContextPath";
|
||||
|
||||
/**
|
||||
* Name of the header that defines the path to the folder where the jsp
|
||||
* files are extracted.
|
||||
*/
|
||||
public static final String RFC66_JSP_EXTRACT_LOCATION = "Jsp-ExtractLocation";
|
||||
|
||||
/**
|
||||
* Name of the servlet context attribute that points to the bundle context.
|
||||
*/
|
||||
public static final String RFC66_OSGI_BUNDLE_CONTEXT = "osgi-bundlecontext";
|
||||
|
||||
/**
|
||||
* Name of the servlet context attribute that points to the bundle object.
|
||||
* We can't always rely on the bundle-context as there might be no such thing.
|
||||
*/
|
||||
public static final String JETTY_OSGI_BUNDLE = "osgi-bundle";
|
||||
|
||||
/**
|
||||
* List of relative pathes within the bundle to the jetty context files.
|
||||
*/
|
||||
public static final String JETTY_CONTEXT_FILE_PATH = "Jetty-ContextFilePath";
|
||||
|
||||
/**
|
||||
* path within the bundle to the folder that contains the basic resources.
|
||||
*/
|
||||
public static final String JETTY_WAR_RESOURCE_PATH = "Jetty-WarResourcePath";
|
||||
|
||||
/**
|
||||
* path within a fragment hosted by a web-bundle to a folder that contains basic resources.
|
||||
* the path is appended to the lookup path where jetty locates static resources
|
||||
*/
|
||||
public static final String JETTY_WAR_FRAGMENT_RESOURCE_PATH = "Jetty-WarFragmentResourcePath";
|
||||
|
||||
/**
|
||||
* path within a fragment hosted by a web-bundle to a folder that contains basic resources.
|
||||
* The path is prefixed to the lookup path where jetty locates static resources:
|
||||
* this will override static resources with the same name in the web-bundle.
|
||||
*/
|
||||
public static final String JETTY_WAR_PREPEND_FRAGMENT_RESOURCE_PATH = "Jetty-WarPrependFragmentResourcePath";
|
||||
|
||||
/**
|
||||
* installation path of webapp bundle
|
||||
*/
|
||||
public static final String JETTY_BUNDLE_ROOT = "bundle.root";
|
||||
|
||||
/**
|
||||
* Extra classpath
|
||||
*/
|
||||
public static final String JETTY_EXTRA_CLASSPATH = "Jetty-extraClasspath";
|
||||
|
||||
/**
|
||||
* web.xml file path
|
||||
*/
|
||||
public static final String JETTY_WEB_XML_PATH = "Jetty-WebXmlFilePath";
|
||||
|
||||
/**
|
||||
* defaultweb.xml file path
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public static final String JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE = "Jetty-bundleInstall";
|
||||
|
||||
/**
|
||||
* Comma separated list of bundles that contain tld file used by the webapp.
|
||||
*/
|
||||
public static final String REQUIRE_TLD_BUNDLE = "Require-TldBundle";
|
||||
/**
|
||||
* Comma separated list of bundles that contain tld file used by the webapp.
|
||||
* 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"};
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.utils.internal;
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -28,6 +28,8 @@ import org.osgi.framework.ServiceListener;
|
|||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.service.packageadmin.PackageAdmin;
|
||||
import org.osgi.service.startlevel.StartLevel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* PackageAdminServiceTracker
|
||||
|
@ -35,11 +37,12 @@ import org.osgi.service.startlevel.StartLevel;
|
|||
* When the PackageAdmin service is activated we can look for the fragments
|
||||
* attached to this bundle and do a fake "activate" on them.
|
||||
* <p>
|
||||
* See particularly the jetty-ee10-osgi-boot-jsp fragment bundle that uses this
|
||||
* See particularly the jetty-ee9-osgi-boot-jsp fragment bundle that uses this
|
||||
* facility.
|
||||
*/
|
||||
public class PackageAdminServiceTracker implements ServiceListener
|
||||
{
|
||||
private static Logger LOG = LoggerFactory.getLogger(PackageAdminServiceTracker.class);
|
||||
private BundleContext _context;
|
||||
|
||||
private List<BundleActivator> _activatedFragments = new ArrayList<>();
|
||||
|
@ -55,26 +58,21 @@ public class PackageAdminServiceTracker implements ServiceListener
|
|||
public static PackageAdminServiceTracker INSTANCE = null;
|
||||
|
||||
public PackageAdminServiceTracker(BundleContext context)
|
||||
throws Exception
|
||||
{
|
||||
INSTANCE = this;
|
||||
_context = context;
|
||||
if (!setup())
|
||||
{
|
||||
try
|
||||
{
|
||||
_context.addServiceListener(this, "(objectclass=" + PackageAdmin.class.getName() + ")");
|
||||
}
|
||||
catch (InvalidSyntaxException e)
|
||||
{
|
||||
e.printStackTrace(); // won't happen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the fragments were activated by this method.
|
||||
*/
|
||||
private boolean setup()
|
||||
throws Exception
|
||||
{
|
||||
ServiceReference sr = _context.getServiceReference(PackageAdmin.class.getName());
|
||||
_fragmentsWereActivated = sr != null;
|
||||
|
@ -110,9 +108,16 @@ public class PackageAdminServiceTracker implements ServiceListener
|
|||
public void serviceChanged(ServiceEvent event)
|
||||
{
|
||||
if (event.getType() == ServiceEvent.REGISTERED)
|
||||
{
|
||||
try
|
||||
{
|
||||
invokeFragmentActivators(event.getServiceReference());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Error invoking fragment activators", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -271,6 +276,7 @@ public class PackageAdminServiceTracker implements ServiceListener
|
|||
}
|
||||
|
||||
private void invokeFragmentActivators(ServiceReference sr)
|
||||
throws Exception
|
||||
{
|
||||
PackageAdmin admin = (PackageAdmin)_context.getService(sr);
|
||||
Bundle[] fragments = admin.getFragments(_context.getBundle());
|
||||
|
@ -281,8 +287,6 @@ public class PackageAdminServiceTracker implements ServiceListener
|
|||
for (Bundle frag : fragments)
|
||||
{
|
||||
// find a convention to look for a class inside the fragment.
|
||||
try
|
||||
{
|
||||
String fragmentActivator = frag.getSymbolicName() + ".FragmentActivator";
|
||||
Class<?> c = Class.forName(fragmentActivator);
|
||||
if (c != null)
|
||||
|
@ -292,11 +296,6 @@ public class PackageAdminServiceTracker implements ServiceListener
|
|||
_activatedFragments.add(bActivator);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stop()
|
|
@ -1,224 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.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.ee10.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.Util;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.Constants;
|
||||
import org.osgi.framework.Filter;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* ServiceContextProvider
|
||||
*
|
||||
* Jetty DeploymentManager Provider that is able to deploy ContextHandlers discovered via OSGi as services.
|
||||
*/
|
||||
public class ServiceContextProvider extends AbstractContextProvider implements ServiceProvider
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractContextProvider.class);
|
||||
|
||||
private Map<ServiceReference, App> _serviceMap = new HashMap<>();
|
||||
|
||||
private ServiceRegistration _serviceRegForServices;
|
||||
|
||||
ServiceTracker _tracker;
|
||||
|
||||
/**
|
||||
* ContextTracker
|
||||
*/
|
||||
public class ContextTracker extends ServiceTracker
|
||||
{
|
||||
|
||||
public ContextTracker(BundleContext bundleContext, Filter filter)
|
||||
{
|
||||
super(bundleContext, filter, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object addingService(ServiceReference reference)
|
||||
{
|
||||
ContextHandler h = (ContextHandler)context.getService(reference);
|
||||
serviceAdded(reference, h);
|
||||
return h;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifiedService(ServiceReference reference, Object service)
|
||||
{
|
||||
removedService(reference, service);
|
||||
addingService(reference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removedService(ServiceReference reference, Object service)
|
||||
{
|
||||
context.ungetService(reference);
|
||||
serviceRemoved(reference, (ContextHandler)service);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean serviceAdded(ServiceReference serviceRef, ContextHandler context)
|
||||
{
|
||||
if (context == null || serviceRef == null)
|
||||
return false;
|
||||
|
||||
if (context instanceof org.eclipse.jetty.ee10.webapp.WebAppContext)
|
||||
return false; //the ServiceWebAppProvider will deploy it
|
||||
|
||||
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);
|
||||
|
||||
String[] keys = serviceRef.getPropertyKeys();
|
||||
Dictionary<String, Object> properties = new Hashtable<>();
|
||||
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 != null ? contextFile : serviceRef.getProperty(Constants.SERVICE_ID));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
{
|
||||
|
||||
BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
|
||||
|
||||
//Start a tracker to find webapps that are osgi services that are targeted to my server name
|
||||
_tracker = new ContextTracker(bundleContext,
|
||||
Util.createFilter(bundleContext, ContextHandler.class.getName(), getServerInstanceWrapper().getManagedServerName()));
|
||||
_tracker.open();
|
||||
|
||||
//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<>();
|
||||
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
|
||||
{
|
||||
if (_tracker != null)
|
||||
_tracker.close();
|
||||
|
||||
//unregister ourselves
|
||||
if (_serviceRegForServices != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_serviceRegForServices.unregister();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to unregister {}", _serviceRegForServices, e);
|
||||
}
|
||||
}
|
||||
super.doStop();
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot;
|
||||
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
/**
|
||||
* ServiceProvider
|
||||
*
|
||||
* Jetty DeploymentManager Provider api for webapps or ContextHandlers that are discovered as OSGi services.
|
||||
*/
|
||||
public interface ServiceProvider
|
||||
{
|
||||
public boolean serviceAdded(ServiceReference ref, ContextHandler handler) throws Exception;
|
||||
|
||||
public boolean serviceRemoved(ServiceReference ref, ContextHandler handler) throws Exception;
|
||||
}
|
|
@ -1,256 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.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.ee10.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.Util;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.Filter;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* ServiceWebAppProvider
|
||||
* <p>
|
||||
* 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 = LoggerFactory.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<>();
|
||||
|
||||
private ServiceRegistration _serviceRegForServices;
|
||||
|
||||
private ServiceTracker webappTracker;
|
||||
|
||||
/**
|
||||
* WebAppTracker
|
||||
*/
|
||||
public class WebAppTracker extends ServiceTracker
|
||||
{
|
||||
/**
|
||||
* @param bundleContext the osgi context
|
||||
* @param filter the osgi filter for the tracker
|
||||
*/
|
||||
public WebAppTracker(BundleContext bundleContext, Filter filter)
|
||||
{
|
||||
super(bundleContext, filter, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object addingService(ServiceReference reference)
|
||||
{
|
||||
WebAppContext wac = (WebAppContext)context.getService(reference);
|
||||
serviceAdded(reference, wac);
|
||||
return wac;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifiedService(ServiceReference reference, Object service)
|
||||
{
|
||||
removedService(reference, service);
|
||||
addingService(reference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removedService(ServiceReference reference, Object service)
|
||||
{
|
||||
serviceRemoved(reference, (WebAppContext)service);
|
||||
context.ungetService(reference);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ServiceApp
|
||||
*/
|
||||
public class ServiceApp extends OSGiApp
|
||||
{
|
||||
|
||||
public ServiceApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary<String, String> 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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
@Override
|
||||
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<String, String> properties = new Hashtable<>();
|
||||
|
||||
String contextPath = (String)serviceRef.getProperty(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
|
||||
if (contextPath == null)
|
||||
return false; //No context path
|
||||
|
||||
String base = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH);
|
||||
|
||||
if (base == null)
|
||||
return false; //No webapp base
|
||||
|
||||
String webdefaultXml = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_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)
|
||||
properties.put(OSGiWebappConstants.JETTY_WEB_XML_PATH, webXml);
|
||||
|
||||
String extraClassPath = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_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)
|
||||
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
|
||||
*/
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
|
||||
|
||||
//Start a tracker to find webapps that are osgi services that are targeted to my server name
|
||||
webappTracker = new WebAppTracker(bundleContext,
|
||||
Util.createFilter(bundleContext, WebAppContext.class.getName(), getServerInstanceWrapper().getManagedServerName()));
|
||||
webappTracker.open();
|
||||
|
||||
//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<>();
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
webappTracker.close();
|
||||
|
||||
//unregister ourselves
|
||||
if (_serviceRegForServices != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_serviceRegForServices.unregister();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to unregister {}", _serviceRegForServices, e);
|
||||
}
|
||||
}
|
||||
super.doStop();
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.internal.serverfactory;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.eclipse.jetty.ee10.osgi.boot.OSGiServerConstants;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.util.tracker.ServiceTrackerCustomizer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* JettyServerServiceTracker
|
||||
*
|
||||
* Tracks instances of Jetty Servers, and configures them so that they can deploy
|
||||
* webapps or ContextHandlers discovered from the OSGi environment.
|
||||
*/
|
||||
public class JettyServerServiceTracker implements ServiceTrackerCustomizer
|
||||
{
|
||||
private static Logger LOG = LoggerFactory.getLogger(JettyServerServiceTracker.class.getName());
|
||||
|
||||
@Override
|
||||
public Object addingService(ServiceReference sr)
|
||||
{
|
||||
Bundle contributor = sr.getBundle();
|
||||
Server server = (Server)contributor.getBundleContext().getService(sr);
|
||||
String name = (String)sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
if (name == null)
|
||||
{
|
||||
throw new IllegalArgumentException("The property " + OSGiServerConstants.MANAGED_JETTY_SERVER_NAME + " is mandatory");
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Adding Server {}", name);
|
||||
ServerInstanceWrapper wrapper = new ServerInstanceWrapper(name);
|
||||
Dictionary<String, Object> props = new Hashtable<>();
|
||||
for (String key : sr.getPropertyKeys())
|
||||
{
|
||||
props.put(key, sr.getProperty(key));
|
||||
}
|
||||
try
|
||||
{
|
||||
wrapper.start(server, props);
|
||||
LOG.info("Started Server {}", name);
|
||||
return wrapper;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Failed to start server {}", name, e);
|
||||
return sr.getBundle().getBundleContext().getService(sr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifiedService(ServiceReference reference, Object service)
|
||||
{
|
||||
removedService(reference, service);
|
||||
addingService(reference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removedService(ServiceReference reference, Object service)
|
||||
{
|
||||
if (service instanceof ServerInstanceWrapper)
|
||||
{
|
||||
ServerInstanceWrapper wrapper = (ServerInstanceWrapper)service;
|
||||
try
|
||||
{
|
||||
wrapper.stop();
|
||||
LOG.info("Stopped Server {}", wrapper.getManagedServerName());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Failed to stop server {}", wrapper.getManagedServerName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,441 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.internal.serverfactory;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Dictionary;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
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.ee10.osgi.boot.BundleContextProvider;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.BundleWebAppProvider;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.JettyBootstrapActivator;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.OSGiDeployer;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.OSGiServerConstants;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.OSGiUndeployer;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.ServiceContextProvider;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.ServiceWebAppProvider;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.internal.webapp.LibExtClassLoaderHelper;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.FakeURLClassLoader;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.TldBundleDiscoverer;
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.Util;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* ServerInstanceWrapper
|
||||
*
|
||||
* Configures and starts a jetty Server instance.
|
||||
*/
|
||||
public class ServerInstanceWrapper
|
||||
{
|
||||
|
||||
/**
|
||||
* The value of this property points to the parent director of the jetty.xml
|
||||
* configuration file currently executed. Everything is passed as a URL to
|
||||
* support the case where the bundle is zipped.
|
||||
*/
|
||||
public static final String PROPERTY_THIS_JETTY_XML_FOLDER_URL = "this.jetty.xml.parent.folder.url";
|
||||
|
||||
private static Collection<TldBundleDiscoverer> __containerTldBundleDiscoverers = new ArrayList<>();
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ServerInstanceWrapper.class.getName());
|
||||
|
||||
private final String _managedServerName;
|
||||
|
||||
/**
|
||||
* The managed jetty server
|
||||
*/
|
||||
private Server _server;
|
||||
|
||||
private ContextHandlerCollection _ctxtCollection;
|
||||
|
||||
/**
|
||||
* This is the class loader that should be the parent classloader of any
|
||||
* webapp classloader. It is in fact the _libExtClassLoader with a trick to
|
||||
* let the TldScanner find the jars where the tld files are.
|
||||
*/
|
||||
private ClassLoader _commonParentClassLoaderForWebapps;
|
||||
|
||||
private DeploymentManager _deploymentManager;
|
||||
|
||||
public static void addContainerTldBundleDiscoverer(TldBundleDiscoverer tldBundleDiscoverer)
|
||||
{
|
||||
__containerTldBundleDiscoverers.add(tldBundleDiscoverer);
|
||||
}
|
||||
|
||||
public static Collection<TldBundleDiscoverer> getContainerTldBundleDiscoverers()
|
||||
{
|
||||
return __containerTldBundleDiscoverers;
|
||||
}
|
||||
|
||||
public static Server configure(Server server, List<URL> jettyConfigurations, Dictionary<String, Object> props) throws Exception
|
||||
{
|
||||
|
||||
if (jettyConfigurations == null || jettyConfigurations.isEmpty())
|
||||
{
|
||||
return server;
|
||||
}
|
||||
|
||||
Map<String, Object> idMap = new HashMap<>();
|
||||
if (server != null)
|
||||
{
|
||||
//Put in a mapping for the id "Server" and the name of the server as the instance being configured
|
||||
idMap.put("Server", server);
|
||||
idMap.put((String)props.get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME), server);
|
||||
}
|
||||
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
if (props != null)
|
||||
{
|
||||
Enumeration<String> en = props.keys();
|
||||
while (en.hasMoreElements())
|
||||
{
|
||||
String key = en.nextElement();
|
||||
Object value = props.get(key);
|
||||
properties.put(key, value.toString());
|
||||
if (server != null)
|
||||
server.setAttribute(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
for (URL jettyConfiguration : jettyConfigurations)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Execute a Jetty configuration file
|
||||
XmlConfiguration config = new XmlConfiguration(Resource.newResource(jettyConfiguration));
|
||||
|
||||
config.getIdMap().putAll(idMap);
|
||||
config.getProperties().putAll(properties);
|
||||
|
||||
// #334062 compute the URL of the folder that contains the
|
||||
// conf file and set it as a property so we can compute relative paths
|
||||
// from it.
|
||||
String urlPath = jettyConfiguration.toString();
|
||||
int lastSlash = urlPath.lastIndexOf('/');
|
||||
if (lastSlash > 4)
|
||||
{
|
||||
urlPath = urlPath.substring(0, lastSlash);
|
||||
config.getProperties().put(PROPERTY_THIS_JETTY_XML_FOLDER_URL, urlPath);
|
||||
}
|
||||
|
||||
Object o = config.configure();
|
||||
if (server == null)
|
||||
server = (Server)o;
|
||||
|
||||
idMap = config.getIdMap();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Configuration error in {}", jettyConfiguration);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* @return the classloader
|
||||
*/
|
||||
public ClassLoader getParentClassLoaderForWebapps()
|
||||
{
|
||||
return _commonParentClassLoaderForWebapps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The deployment manager registered on this server.
|
||||
*/
|
||||
public DeploymentManager getDeploymentManager()
|
||||
{
|
||||
return _deploymentManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The app provider registered on this server.
|
||||
*/
|
||||
public Server getServer()
|
||||
{
|
||||
return _server;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The collection of context handlers
|
||||
*/
|
||||
public ContextHandlerCollection getContextHandlerCollection()
|
||||
{
|
||||
return _ctxtCollection;
|
||||
}
|
||||
|
||||
public void start(Server server, Dictionary<String, Object> props) throws Exception
|
||||
{
|
||||
_server = server;
|
||||
ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
|
||||
try
|
||||
{
|
||||
List<URL> sharedURLs = getManagedJettySharedLibFolderUrls(props);
|
||||
|
||||
// passing this bundle's classloader as the context classloader
|
||||
// makes sure there is access to all the jetty's bundles
|
||||
ClassLoader libExtClassLoader = LibExtClassLoaderHelper.createLibExtClassLoader(null, sharedURLs, JettyBootstrapActivator.class.getClassLoader());
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("LibExtClassLoader = {}", libExtClassLoader);
|
||||
|
||||
Thread.currentThread().setContextClassLoader(libExtClassLoader);
|
||||
|
||||
String jettyConfigurationUrls = (String)props.get(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS);
|
||||
List<URL> jettyConfigurations = jettyConfigurationUrls != null ? Util.fileNamesAsURLs(jettyConfigurationUrls, StringUtil.DEFAULT_DELIMS) : null;
|
||||
|
||||
_server = configure(server, jettyConfigurations, props);
|
||||
|
||||
init();
|
||||
|
||||
//if support for jsp is enabled, we need to convert locations of bundles that contain tlds into urls.
|
||||
//these are tlds that we want jasper to treat as if they are on the container's classpath. Web bundles
|
||||
//can use the Require-TldBundle MANIFEST header to name other tld-containing bundles that should be regarded
|
||||
//as on the webapp classpath.
|
||||
if (!__containerTldBundleDiscoverers.isEmpty())
|
||||
{
|
||||
Set<URL> urls = new HashSet<>();
|
||||
//discover bundles with tlds that need to be on the container's classpath as URLs
|
||||
for (TldBundleDiscoverer d : __containerTldBundleDiscoverers)
|
||||
{
|
||||
URL[] list = d.getUrlsForBundlesWithTlds(_deploymentManager, BundleFileLocatorHelperFactory.getFactory().getHelper());
|
||||
if (list != null)
|
||||
{
|
||||
for (URL u : list)
|
||||
{
|
||||
urls.add(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
_commonParentClassLoaderForWebapps = new FakeURLClassLoader(libExtClassLoader, urls.toArray(new URL[urls.size()]));
|
||||
}
|
||||
else
|
||||
_commonParentClassLoaderForWebapps = libExtClassLoader;
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("common classloader = {}", _commonParentClassLoaderForWebapps);
|
||||
|
||||
server.start();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (server != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
LOG.trace("IGNORED", x);
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(contextCl);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_server.isRunning())
|
||||
{
|
||||
_server.stop();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Failed to stop server", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called after the server is configured.
|
||||
*
|
||||
* It is assumed the server has already been configured with the ContextHandlerCollection structure.
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
// Get the context handler
|
||||
_ctxtCollection = (ContextHandlerCollection)_server.getDescendant(ContextHandlerCollection.class);
|
||||
|
||||
if (_ctxtCollection == null)
|
||||
throw new IllegalStateException("ERROR: No ContextHandlerCollection configured in Server");
|
||||
|
||||
List<String> providerClassNames = new ArrayList<>();
|
||||
|
||||
// get a deployerManager and some providers
|
||||
Collection<DeploymentManager> deployers = _server.getBeans(DeploymentManager.class);
|
||||
if (deployers != null && !deployers.isEmpty())
|
||||
{
|
||||
_deploymentManager = deployers.iterator().next();
|
||||
|
||||
for (AppProvider provider : _deploymentManager.getAppProviders())
|
||||
{
|
||||
providerClassNames.add(provider.getClass().getName());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//add some kind of default
|
||||
_deploymentManager = new DeploymentManager();
|
||||
_deploymentManager.setContexts(_ctxtCollection);
|
||||
_server.addBean(_deploymentManager);
|
||||
}
|
||||
|
||||
_deploymentManager.setUseStandardBindings(false);
|
||||
List<AppLifeCycle.Binding> deploymentLifeCycleBindings = new ArrayList<>();
|
||||
deploymentLifeCycleBindings.add(new OSGiDeployer(this));
|
||||
deploymentLifeCycleBindings.add(new StandardStarter());
|
||||
deploymentLifeCycleBindings.add(new StandardStopper());
|
||||
deploymentLifeCycleBindings.add(new OSGiUndeployer(this));
|
||||
_deploymentManager.setLifeCycleBindings(deploymentLifeCycleBindings);
|
||||
|
||||
if (!providerClassNames.contains(BundleWebAppProvider.class.getName()))
|
||||
{
|
||||
// create it on the fly with reasonable default values.
|
||||
try
|
||||
{
|
||||
BundleWebAppProvider webAppProvider = new BundleWebAppProvider(this);
|
||||
_deploymentManager.addAppProvider(webAppProvider);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Failed to add BundleAppProvider to DeploymentManager", e);
|
||||
}
|
||||
}
|
||||
|
||||
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("Failed to add ServiceWebAppProvider to DeploymentManager", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!providerClassNames.contains(BundleContextProvider.class.getName()))
|
||||
{
|
||||
try
|
||||
{
|
||||
BundleContextProvider contextProvider = new BundleContextProvider(this);
|
||||
_deploymentManager.addAppProvider(contextProvider);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Failed to add BundleContextProvider to DeploymentManager", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!providerClassNames.contains(ServiceContextProvider.class.getName()))
|
||||
{
|
||||
try
|
||||
{
|
||||
ServiceContextProvider contextProvider = new ServiceContextProvider(this);
|
||||
_deploymentManager.addAppProvider(contextProvider);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Failed to add ServiceContextProvider to DeploymentManager", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Jetty Shared Lib Folder URLs in a form that is suitable for
|
||||
* {@link LibExtClassLoaderHelper} to use.
|
||||
*
|
||||
* @param props the properties to look for the configuration in
|
||||
* @return the list of URLs found, or null if none found
|
||||
*/
|
||||
private List<URL> getManagedJettySharedLibFolderUrls(Dictionary<String, Object> props)
|
||||
{
|
||||
String sharedURLs = (String)props.get(OSGiServerConstants.MANAGED_JETTY_SHARED_LIB_FOLDER_URLS);
|
||||
if (StringUtil.isBlank(sharedURLs))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<URL> libURLs = new ArrayList<>();
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(sharedURLs, StringUtil.DEFAULT_DELIMS, false);
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String tok = tokenizer.nextToken();
|
||||
try
|
||||
{
|
||||
URL url = new URL(tok);
|
||||
url = BundleFileLocatorHelperFactory.getFactory().getHelper().getFileURL(url);
|
||||
if (url.getProtocol().equals("file"))
|
||||
{
|
||||
libURLs.add(new URL("jar:" + url.toExternalForm() + "!/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Unrecognized Jetty Shared Lib URL: {}", url);
|
||||
}
|
||||
}
|
||||
catch (Throwable mfe)
|
||||
{
|
||||
LOG.warn("Unable to process legacy lib folder {}", tok, mfe);
|
||||
}
|
||||
}
|
||||
return libURLs;
|
||||
}
|
||||
}
|
|
@ -1,196 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.internal.webapp;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* LibExtClassLoaderHelper
|
||||
* <p>
|
||||
* Helper to create a URL class-loader with the jars inside
|
||||
* <code>${jetty.home}/lib/ext</code> and <code>${jetty.home}/resources</code>. In an ideal world, every
|
||||
* library is an OSGi bundle that does loads nicely. To support standard jars or
|
||||
* bundles that cannot be loaded in the current OSGi environment, we support
|
||||
* inserting the jars in the usual jetty/lib/ext folders in the proper classpath
|
||||
* for the webapps.
|
||||
* <p>
|
||||
* The drawback is that those jars will not be available in the OSGi
|
||||
* classloader.
|
||||
* <p>
|
||||
* Alternatives to placing jars in lib/ext:
|
||||
* <ol>
|
||||
* <li>Bundle the jars in an osgi bundle. Have the webapp(s) that need these jars
|
||||
* depend on that bundle.</li>
|
||||
* <li>Bundle those jars in an osgi bundle-fragment that targets the
|
||||
* jetty-bootstrap bundle</li>
|
||||
* <li>Use equinox Buddy-Policy: register a buddy of the jetty bootstrapper
|
||||
* bundle. (Note: it will work only on equinox)</li>
|
||||
* </ol>
|
||||
*/
|
||||
public class LibExtClassLoaderHelper
|
||||
{
|
||||
|
||||
/**
|
||||
* IFilesInJettyHomeResourcesProcessor
|
||||
*
|
||||
* Interface for callback impls
|
||||
*/
|
||||
public interface IFilesInJettyHomeResourcesProcessor
|
||||
{
|
||||
void processFilesInResourcesFolder(File jettyHome, Map<String, File> filesInResourcesFolder);
|
||||
}
|
||||
|
||||
public static final Set<IFilesInJettyHomeResourcesProcessor> registeredFilesInJettyHomeResourcesProcessors = new HashSet<>();
|
||||
|
||||
/**
|
||||
* @param jettyHome the jetty home
|
||||
* @param parentClassLoader the parent classloader
|
||||
* @return a url classloader with the jars of resources, lib/ext and the
|
||||
* jars passed in the other argument. The parent classloader usually
|
||||
* is the JettyBootStrapper (an osgi classloader.
|
||||
* @throws MalformedURLException if the jetty home reference is invalid
|
||||
*/
|
||||
public static ClassLoader createLibEtcClassLoader(File jettyHome, ClassLoader parentClassLoader) throws MalformedURLException
|
||||
{
|
||||
if (jettyHome == null)
|
||||
{
|
||||
return parentClassLoader;
|
||||
}
|
||||
ArrayList<URL> urls = new ArrayList<>();
|
||||
File jettyResources = new File(jettyHome, "resources");
|
||||
if (jettyResources.exists())
|
||||
{
|
||||
// make sure it contains something else than README:
|
||||
Map<String, File> jettyResFiles = new HashMap<>();
|
||||
for (File f : jettyResources.listFiles())
|
||||
{
|
||||
jettyResFiles.put(f.getName(), f);
|
||||
if (f.getName().toLowerCase(Locale.ENGLISH).startsWith("readme"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (urls.isEmpty())
|
||||
{
|
||||
urls.add(jettyResources.toURI().toURL());
|
||||
}
|
||||
}
|
||||
}
|
||||
processFilesInResourcesFolder(jettyHome, jettyResFiles);
|
||||
}
|
||||
File libExt = new File(jettyHome, "lib/ext");
|
||||
if (libExt.exists())
|
||||
{
|
||||
for (File f : libExt.listFiles())
|
||||
{
|
||||
if (FileID.isJavaArchive(f.getName()))
|
||||
{
|
||||
// cheap to tolerate folders so let's do it.
|
||||
URL url = f.toURI().toURL();
|
||||
if (f.isFile())
|
||||
{
|
||||
// is this necessary anyways?
|
||||
url = new URL("jar:" + url.toString() + "!/");
|
||||
}
|
||||
urls.add(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new URLClassLoader(urls.toArray(new URL[urls.size()]), parentClassLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jarsContainerOrJars the jars via file references
|
||||
* @param otherJarsOrFolder more jars via url references
|
||||
* @param parentClassLoader the parent classloader
|
||||
* @return a url classloader with the jars of resources, lib/ext and the
|
||||
* jars passed in the other argument. The parent classloader usually
|
||||
* is the JettyBootStrapper (an osgi classloader). If there was no
|
||||
* extra jars to insert, then just return the parentClassLoader.
|
||||
* @throws MalformedURLException if there is a bad jar file reference
|
||||
*/
|
||||
public static ClassLoader createLibExtClassLoader(List<File> jarsContainerOrJars, List<URL> otherJarsOrFolder, ClassLoader parentClassLoader)
|
||||
throws MalformedURLException
|
||||
{
|
||||
if (jarsContainerOrJars == null && otherJarsOrFolder == null)
|
||||
{
|
||||
return parentClassLoader;
|
||||
}
|
||||
List<URL> urls = new ArrayList<>();
|
||||
if (otherJarsOrFolder != null)
|
||||
{
|
||||
urls.addAll(otherJarsOrFolder);
|
||||
}
|
||||
if (jarsContainerOrJars != null)
|
||||
{
|
||||
for (File libExt : jarsContainerOrJars)
|
||||
{
|
||||
if (libExt.isDirectory())
|
||||
{
|
||||
for (File f : libExt.listFiles())
|
||||
{
|
||||
if (FileID.isJavaArchive(f.getName()))
|
||||
{
|
||||
// cheap to tolerate folders so let's do it.
|
||||
URL url = f.toURI().toURL();
|
||||
if (f.isFile())
|
||||
{
|
||||
// is this necessary anyways?
|
||||
url = new URL("jar:" + url.toString() + "!/");
|
||||
}
|
||||
urls.add(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new URLClassLoader(urls.toArray(new URL[urls.size()]), parentClassLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* When we find files typically used for central logging configuration we do
|
||||
* what it takes in this method to do what the user expects. Without
|
||||
* depending too much directly on a particular logging framework.
|
||||
* <p>
|
||||
* We can afford to do some implementation specific code for a logging
|
||||
* framework only in a fragment.
|
||||
* <p>
|
||||
* Trying to configure log4j and logback in here.
|
||||
* <p>
|
||||
* We recommend that slf4j jars are all placed in the osgi framework. And a
|
||||
* single implementation if possible packaged as an osgi bundle is there.
|
||||
*
|
||||
* @param jettyHome the jetty home reference
|
||||
* @param childrenFiles the map of child files
|
||||
*/
|
||||
protected static void processFilesInResourcesFolder(File jettyHome, Map<String, File> childrenFiles)
|
||||
{
|
||||
for (IFilesInJettyHomeResourcesProcessor processor : registeredFilesInJettyHomeResourcesProcessors)
|
||||
{
|
||||
processor.processFilesInResourcesFolder(jettyHome, childrenFiles);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.utils;
|
||||
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.internal.DefaultBundleClassLoaderHelper;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
/**
|
||||
* BundleClassLoaderHelper
|
||||
* <p>
|
||||
* Is there a clean OSGi way to go from the Bundle object to the classloader of
|
||||
* the Bundle ? You can certainly take a class inside the bundle and get the
|
||||
* bundle's classloader that way. Getting the classloader directly from the
|
||||
* bundle would be nice.
|
||||
* <p>
|
||||
* We could use fragments that are specific to each OSGi implementation. Using
|
||||
* introspection here to keep packaging simple and avoid the multiplication of
|
||||
* the jars.
|
||||
* <p>
|
||||
* The default implementation relies on introspection and supports equinox-3.5
|
||||
* and felix-2.0.0
|
||||
*/
|
||||
public interface BundleClassLoaderHelper
|
||||
{
|
||||
|
||||
/**
|
||||
* The name of the custom implementation for this interface in a fragment.
|
||||
*/
|
||||
public static final String CLASS_NAME = "org.eclipse.jetty.ee10.osgi.boot.utils.BundleClassLoaderHelperImpl";
|
||||
|
||||
/**
|
||||
* The default instance supports felix and equinox
|
||||
*/
|
||||
public static BundleClassLoaderHelper DEFAULT = new DefaultBundleClassLoaderHelper();
|
||||
|
||||
/**
|
||||
* @param bundle the bundle
|
||||
* @return The classloader of a given bundle. Assuming the bundle is
|
||||
* started.
|
||||
*/
|
||||
public ClassLoader getBundleClassLoader(Bundle bundle);
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.utils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* BundleClassLoaderHelperFactory
|
||||
*
|
||||
* Get a class loader helper adapted for the particular osgi environment.
|
||||
*/
|
||||
public class BundleClassLoaderHelperFactory
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.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)
|
||||
.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.trace("IGNORED", t);
|
||||
}
|
||||
|
||||
return helper;
|
||||
}
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.internal.DefaultFileLocatorHelper;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
/**
|
||||
* BundleFileLocatorHelper
|
||||
* <p>
|
||||
* From a bundle to its location on the filesystem. Assumes the bundle is not a
|
||||
* jar.
|
||||
*/
|
||||
public interface BundleFileLocatorHelper
|
||||
{
|
||||
|
||||
/**
|
||||
* The name of the custom implementation for this interface in a fragment.
|
||||
*/
|
||||
public static final String CLASS_NAME = "org.eclipse.jetty.ee10.osgi.boot.utils.FileLocatorHelperImpl";
|
||||
|
||||
/**
|
||||
* The default instance supports felix and equinox
|
||||
*/
|
||||
public static BundleFileLocatorHelper DEFAULT = new DefaultFileLocatorHelper();
|
||||
|
||||
/**
|
||||
* Works with equinox, felix, nuxeo and probably more. Not exactly in the
|
||||
* spirit of OSGi but quite necessary to support self-contained webapps and
|
||||
* other situations.
|
||||
* <p>
|
||||
* Currently only works with bundles that are not jar.
|
||||
*
|
||||
* @param bundle The bundle
|
||||
* @return Its installation location as a file.
|
||||
* @throws Exception if unable to get the install location
|
||||
*/
|
||||
public File getBundleInstallLocation(Bundle bundle) throws Exception;
|
||||
|
||||
/**
|
||||
* Locate a file inside a bundle.
|
||||
*
|
||||
* @param bundle the bundle
|
||||
* @param path the path
|
||||
* @return file the file object
|
||||
* @throws Exception if unable to get the file
|
||||
*/
|
||||
public File getFileInBundle(Bundle bundle, String path) throws Exception;
|
||||
|
||||
/**
|
||||
* If the bundle is a jar, returns the jar. If the bundle is a folder, look
|
||||
* inside it and search for jars that it returns.
|
||||
* <p>
|
||||
* Good enough for our purpose (TldLocationsCache when it scans for tld
|
||||
* files inside jars alone. In fact we only support the second situation for
|
||||
* development purpose where the bundle was imported in pde and the classes
|
||||
* kept in a jar.
|
||||
*
|
||||
* @param bundle the bundle
|
||||
* @return The jar(s) file that is either the bundle itself, either the jars
|
||||
* embedded inside it.
|
||||
* @throws Exception if unable to locate the jars
|
||||
*/
|
||||
public File[] locateJarsInsideBundle(Bundle bundle) throws Exception;
|
||||
|
||||
/**
|
||||
* Helper method equivalent to Bundle#getEntry(String entryPath) except that
|
||||
* it searches for entries in the fragments by using the findEntries method.
|
||||
*
|
||||
* @param bundle the bundle
|
||||
* @param entryPath the entry path
|
||||
* @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 <code>file://</code> or <code>jar://</code> url
|
||||
* already. Other OSGi implementations have not been tested
|
||||
* <p>
|
||||
* Get a URL to the bundle entry that uses a common protocol (i.e. <code>file:</code>
|
||||
* <code>jar:</code> or <code>http:</code> etc.).
|
||||
*
|
||||
* @param url the url
|
||||
* @return a URL to the bundle entry that uses a common protocol
|
||||
* @throws Exception if unable to get the local url
|
||||
*/
|
||||
public URL getLocalURL(URL url) throws Exception;
|
||||
|
||||
/**
|
||||
* Only useful for equinox: on felix we get the <code>file://</code> url already. Other
|
||||
* OSGi implementations have not been tested
|
||||
* <p>
|
||||
* Get a URL to the content of the bundle entry that uses the <code>file:</code>
|
||||
* protocol. The content of the bundle entry may be downloaded or extracted
|
||||
* to the local file system in order to create a file: URL.
|
||||
*
|
||||
* @param url the url
|
||||
* @return a URL to the content of the bundle entry that uses the file:
|
||||
* protocol
|
||||
* @throws Exception if unable to get the file url
|
||||
*/
|
||||
public URL getFileURL(URL url) throws Exception;
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.utils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* BundleFileLocatorHelperFactory
|
||||
*
|
||||
* Obtain a helper for locating files based on the bundle.
|
||||
*/
|
||||
public class BundleFileLocatorHelperFactory
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.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)
|
||||
.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.trace("IGNORED", t);
|
||||
}
|
||||
return helper;
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.utils;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.service.event.Event;
|
||||
import org.osgi.service.event.EventAdmin;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
|
||||
/**
|
||||
* Utility class for emitting OSGi EventAdmin events
|
||||
*/
|
||||
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 ServiceTracker _serviceTracker;
|
||||
|
||||
private EventSender()
|
||||
{
|
||||
_myBundle = FrameworkUtil.getBundle(EventSender.class);
|
||||
_serviceTracker = new ServiceTracker(_myBundle.getBundleContext(), EventAdmin.class.getName(), null);
|
||||
_serviceTracker.open();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
EventAdmin service = (EventAdmin)_serviceTracker.getService();
|
||||
if (service != null)
|
||||
{
|
||||
Dictionary<String, Object> props = new Hashtable<>();
|
||||
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);
|
||||
|
||||
service.sendEvent(new Event(topic, props));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.utils;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
/**
|
||||
* FakeURLClassLoader
|
||||
* <p>
|
||||
* A URLClassloader that overrides the getURLs() method to return the list
|
||||
* of urls passed in to the constructor, but otherwise acts as if it has no
|
||||
* urls, which would cause it to delegate to the parent classloader (in this
|
||||
* case an OSGi classloader).
|
||||
* <p>
|
||||
* The main use of this class is with jars containing tlds. Jasper expects a
|
||||
* URL classloader to inspect for jars with tlds.
|
||||
*/
|
||||
public class FakeURLClassLoader extends URLClassLoader
|
||||
{
|
||||
private URL[] _jars;
|
||||
|
||||
public FakeURLClassLoader(ClassLoader osgiClassLoader, URL[] jars)
|
||||
{
|
||||
super(new URL[]{}, osgiClassLoader);
|
||||
_jars = jars;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jars that contains tlds so that TldLocationsCache or
|
||||
* TldScanner can find them.
|
||||
*/
|
||||
@Override
|
||||
public URL[] getURLs()
|
||||
{
|
||||
return _jars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (_jars != null)
|
||||
{
|
||||
for (URL u : _jars)
|
||||
{
|
||||
builder.append(" " + u.toString());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
else
|
||||
return super.toString();
|
||||
}
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.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.osgi.framework.Bundle;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 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 = LoggerFactory.getLogger(OSGiClassLoader.class);
|
||||
|
||||
private Bundle _bundle;
|
||||
private ClassLoader _osgiBundleClassLoader;
|
||||
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
|
||||
*/
|
||||
@Override
|
||||
public URL getResource(String name)
|
||||
{
|
||||
URL url = null;
|
||||
boolean triedParent = false;
|
||||
|
||||
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 && !triedParent)
|
||||
{
|
||||
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 Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
|
||||
{
|
||||
synchronized (getClassLoadingLock(name))
|
||||
{
|
||||
Class<?> c = findLoadedClass(name);
|
||||
ClassNotFoundException ex = null;
|
||||
boolean triedParent = false;
|
||||
|
||||
if (c == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
c = this.findClass(name);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
ex = e;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == null && _parent != null && !triedParent)
|
||||
c = _parent.loadClass(name);
|
||||
|
||||
if (c == null)
|
||||
throw ex;
|
||||
|
||||
if (resolve)
|
||||
resolveClass(c);
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("loaded {} from {}", c, 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);
|
||||
return Collections.enumeration(toList(osgiUrls, urls));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
return _osgiBundleClassLoader.loadClass(name);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private List<URL> toList(Enumeration<URL> e, Enumeration<URL> e2)
|
||||
{
|
||||
List<URL> list = new ArrayList<>();
|
||||
while (e != null && e.hasMoreElements())
|
||||
{
|
||||
list.add(e.nextElement());
|
||||
}
|
||||
while (e2 != null && e2.hasMoreElements())
|
||||
{
|
||||
list.add(e2.nextElement());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.utils;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle.AbstractLifeCycleListener;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
|
||||
/**
|
||||
* ServerConnectorListener
|
||||
*
|
||||
* This is for test support, where we need jetty to run on a random port, and we need
|
||||
* a client to be able to find out which port was picked.
|
||||
*/
|
||||
public class ServerConnectorListener extends AbstractLifeCycleListener
|
||||
{
|
||||
|
||||
private Path _filePath;
|
||||
private String _sysPropertyName;
|
||||
|
||||
@Override
|
||||
public void lifeCycleStarted(LifeCycle event)
|
||||
{
|
||||
if (getFilePath() != null)
|
||||
{
|
||||
try (FileWriter writer = new FileWriter(getFilePath().toFile()))
|
||||
{
|
||||
Files.deleteIfExists(_filePath);
|
||||
writer.write(((ServerConnector)event).getLocalPort());
|
||||
writer.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (getSysPropertyName() != null)
|
||||
{
|
||||
System.setProperty(_sysPropertyName, String.valueOf(((ServerConnector)event).getLocalPort()));
|
||||
}
|
||||
super.lifeCycleStarted(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the filePath
|
||||
*/
|
||||
public Path getFilePath()
|
||||
{
|
||||
return _filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filePath the filePath to set
|
||||
*/
|
||||
public void setFilePath(Path filePath)
|
||||
{
|
||||
_filePath = filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sysPropertyName
|
||||
*/
|
||||
public String getSysPropertyName()
|
||||
{
|
||||
return _sysPropertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sysPropertyName the sysPropertyName to set
|
||||
*/
|
||||
public void setSysPropertyName(String sysPropertyName)
|
||||
{
|
||||
_sysPropertyName = sysPropertyName;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.utils;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
|
||||
/**
|
||||
* TldBundleDiscoverer
|
||||
*
|
||||
* Convert bundles that contain tlds into URL locations for consumption by jasper.
|
||||
*/
|
||||
public interface TldBundleDiscoverer
|
||||
{
|
||||
/**
|
||||
* Find bundles that contain tlds and convert into URL references to their location.
|
||||
*
|
||||
* @param manager The {@link DeploymentManager} instance to use
|
||||
* @param fileLocator the {@link BundleFileLocatorHelper} instance to use
|
||||
* @return array of URLs representing locations of tld containing bundles
|
||||
* @throws Exception In case of errors during resolving TLDs files
|
||||
*/
|
||||
URL[] getUrlsForBundlesWithTlds(DeploymentManager manager, BundleFileLocatorHelper fileLocator) throws Exception;
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.utils;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Dictionary;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.eclipse.jetty.ee10.osgi.boot.OSGiServerConstants;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.Filter;
|
||||
import org.osgi.framework.InvalidSyntaxException;
|
||||
|
||||
/**
|
||||
* Various useful functions utility methods for OSGi wide use.
|
||||
*/
|
||||
public class Util
|
||||
{
|
||||
/**
|
||||
* Create an osgi filter for the given classname and server name.
|
||||
*
|
||||
* @param bundleContext the {@link BundleContext} instance to use
|
||||
* @param classname the class to match on the filter
|
||||
* @param managedServerName the name of the jetty server instance
|
||||
* @return a new filter
|
||||
* @throws InvalidSyntaxException If the filter contains an invalid string that cannot be parsed.
|
||||
*/
|
||||
public static Filter createFilter(BundleContext bundleContext, String classname, String managedServerName) throws InvalidSyntaxException
|
||||
{
|
||||
if (StringUtil.isBlank(managedServerName) || managedServerName.equals(OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME))
|
||||
{
|
||||
return bundleContext.createFilter("(&(objectclass=" + classname + ")(|(managedServerName=" + managedServerName + ")(!(managedServerName=*))))");
|
||||
}
|
||||
else
|
||||
{
|
||||
return bundleContext.createFilter("(&(objectclass=" + classname + ")(managedServerName=" + managedServerName + "))");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a manifest header.
|
||||
*
|
||||
* @param name the name of the header
|
||||
* @param altName an alternative name for the header (useful for deprecated names)
|
||||
* @param manifest the dictionary
|
||||
* @return the value from the manifest
|
||||
*/
|
||||
public static String getManifestHeaderValue(String name, String altName, Dictionary<String, String> manifest)
|
||||
{
|
||||
if (manifest == null)
|
||||
return null;
|
||||
if (name == null && altName == null)
|
||||
return null;
|
||||
if (name != null)
|
||||
return (String)manifest.get(name);
|
||||
return (String)manifest.get(altName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a manifest header.
|
||||
*
|
||||
* @param name the name of the header
|
||||
* @param manifest the dictionary
|
||||
* @return the value from the manifest
|
||||
*/
|
||||
public static String getManifestHeaderValue(String name, Dictionary<String, String> manifest)
|
||||
{
|
||||
return getManifestHeaderValue(name, null, manifest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Treating the string as a separated list of filenames,
|
||||
* convert and return the list of urls.
|
||||
*
|
||||
* @param val the separated list of filenames
|
||||
* @param delims the separators (default is <code>,;</code>)
|
||||
* @return the list of URLs found in the input list
|
||||
* @throws Exception if unable to convert entry to a URL
|
||||
*/
|
||||
public static List<URL> fileNamesAsURLs(String val, String delims)
|
||||
throws Exception
|
||||
{
|
||||
String separators = StringUtil.DEFAULT_DELIMS;
|
||||
if (delims == null)
|
||||
delims = separators;
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(val, delims, false);
|
||||
List<URL> urls = new ArrayList<>();
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
urls.add(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(new URL(tokenizer.nextToken())));
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
public static void setProperty(Dictionary<String, Object> properties, String key, Object value)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
properties.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* recursively substitute the <code>${sysprop}</code> by their actual system property.
|
||||
* <code>${sysprop,defaultvalue}</code> will use <code>'defaultvalue'</code> as the value if no
|
||||
* sysprop is defined. Not the most efficient code but we are shooting for
|
||||
* simplicity and speed of development here.
|
||||
*
|
||||
* @param value the input string
|
||||
* @return the string with replaced properties
|
||||
*/
|
||||
public static String resolvePropertyValue(String value)
|
||||
{
|
||||
int ind = value.indexOf("${");
|
||||
if (ind == -1)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
int ind2 = value.indexOf('}', ind);
|
||||
if (ind2 == -1)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
String sysprop = value.substring(ind + 2, ind2);
|
||||
String defaultValue = null;
|
||||
int comma = sysprop.indexOf(',');
|
||||
if (comma != -1 && comma + 1 != sysprop.length())
|
||||
{
|
||||
defaultValue = sysprop.substring(comma + 1);
|
||||
defaultValue = resolvePropertyValue(defaultValue);
|
||||
sysprop = sysprop.substring(0, comma);
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValue = "${" + sysprop + "}";
|
||||
}
|
||||
|
||||
String v = System.getProperty(sysprop);
|
||||
|
||||
String reminder = value.length() > ind2 + 1 ? value.substring(ind2 + 1) : "";
|
||||
reminder = resolvePropertyValue(reminder);
|
||||
if (v != null)
|
||||
{
|
||||
return value.substring(0, ind) + v + reminder;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value.substring(0, ind) + defaultValue + reminder;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,428 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.utils.internal;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.BundleClassLoaderHelper;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* DefaultBundleClassLoaderHelper
|
||||
* <p>
|
||||
* Default implementation of the BundleClassLoaderHelper. Uses introspection to
|
||||
* support equinox-3.5 and felix-2.0.0
|
||||
*/
|
||||
public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(BundleClassLoaderHelper.class);
|
||||
|
||||
private static enum OSGiContainerType
|
||||
{
|
||||
EquinoxOld, EquinoxLuna, FelixOld, Felix403, Concierge
|
||||
}
|
||||
|
||||
;
|
||||
private static OSGiContainerType osgiContainer;
|
||||
private static Class<?> Equinox_BundleHost_Class;
|
||||
private static Class<?> Equinox_EquinoxBundle_Class;
|
||||
private static Class<?> Felix_BundleImpl_Class;
|
||||
private static Class<?> Felix_BundleWiring_Class;
|
||||
//old equinox
|
||||
private static Method Equinox_BundleHost_getBundleLoader_method;
|
||||
private static Method Equinox_BundleLoader_createClassLoader_method;
|
||||
//new equinox
|
||||
private static Method Equinox_EquinoxBundle_getModuleClassLoader_Method;
|
||||
|
||||
//new felix
|
||||
private static Method Felix_BundleImpl_Adapt_Method;
|
||||
//old felix
|
||||
private static Field Felix_BundleImpl_m_Modules_Field;
|
||||
private static Field Felix_ModuleImpl_m_ClassLoader_Field;
|
||||
private static Method Felix_BundleWiring_getClassLoader_Method;
|
||||
|
||||
// Concierge
|
||||
private static Class<?> Concierge_BundleImpl_Class;
|
||||
private static Class<?> Concierge_BundleWiring_Class;
|
||||
private static Method Concierge_BundleImpl_Adapt_Method;
|
||||
private static Method Concierge_BundleWiring_getClassLoader_Method;
|
||||
|
||||
private static void checkContainerType(Bundle bundle)
|
||||
{
|
||||
if (osgiContainer != null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Equinox_BundleHost_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost");
|
||||
osgiContainer = OSGiContainerType.EquinoxOld;
|
||||
return;
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
LOG.trace("IGNORED", e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Equinox_EquinoxBundle_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.framework.EquinoxBundle");
|
||||
osgiContainer = OSGiContainerType.EquinoxLuna;
|
||||
return;
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
LOG.trace("IGNORED", e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//old felix or new felix?
|
||||
Felix_BundleImpl_Class = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl");
|
||||
try
|
||||
{
|
||||
Felix_BundleImpl_Adapt_Method = Felix_BundleImpl_Class.getDeclaredMethod("adapt", new Class[]{Class.class});
|
||||
osgiContainer = OSGiContainerType.Felix403;
|
||||
return;
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
osgiContainer = OSGiContainerType.FelixOld;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
LOG.trace("IGNORED", e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Concierge_BundleImpl_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.concierge.BundleImpl");
|
||||
osgiContainer = OSGiContainerType.Concierge;
|
||||
return;
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
LOG.trace("IGNORED", e);
|
||||
}
|
||||
|
||||
LOG.warn("Unknown OSGi container type");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assuming the bundle is started.
|
||||
*
|
||||
* @param bundle the bundle
|
||||
* @return classloader object
|
||||
*/
|
||||
@Override
|
||||
public ClassLoader getBundleClassLoader(Bundle bundle)
|
||||
{
|
||||
String bundleActivator = (String)bundle.getHeaders().get("Bundle-Activator");
|
||||
|
||||
if (bundleActivator == null)
|
||||
{
|
||||
bundleActivator = (String)bundle.getHeaders().get("Jetty-ClassInBundle");
|
||||
}
|
||||
if (bundleActivator != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return bundle.loadClass(bundleActivator).getClassLoader();
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
LOG.warn("Unable to load bundle activator {}", bundleActivator, e);
|
||||
}
|
||||
}
|
||||
|
||||
// resort to introspection
|
||||
return getBundleClassLoaderForContainer(bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private ClassLoader getBundleClassLoaderForContainer(Bundle bundle)
|
||||
{
|
||||
checkContainerType(bundle);
|
||||
if (osgiContainer == null)
|
||||
{
|
||||
LOG.warn("No classloader for unknown OSGi container type");
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (osgiContainer)
|
||||
{
|
||||
case EquinoxOld:
|
||||
case EquinoxLuna:
|
||||
{
|
||||
return internalGetEquinoxBundleClassLoader(bundle);
|
||||
}
|
||||
|
||||
case FelixOld:
|
||||
case Felix403:
|
||||
{
|
||||
return internalGetFelixBundleClassLoader(bundle);
|
||||
}
|
||||
|
||||
case Concierge:
|
||||
{
|
||||
return internalGetConciergeBundleClassLoader(bundle);
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
LOG.warn("No classloader found for bundle {}", bundle.getSymbolicName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static ClassLoader internalGetEquinoxBundleClassLoader(Bundle bundle)
|
||||
{
|
||||
if (osgiContainer == OSGiContainerType.EquinoxOld)
|
||||
{
|
||||
String bundleLoaderName = "org.eclipse.osgi.internal.loader.BundleLoader";
|
||||
try
|
||||
{
|
||||
if (Equinox_BundleHost_getBundleLoader_method == null)
|
||||
{
|
||||
Equinox_BundleHost_getBundleLoader_method =
|
||||
Equinox_BundleHost_Class.getDeclaredMethod("getBundleLoader", new Class[]{});
|
||||
Equinox_BundleHost_getBundleLoader_method.setAccessible(true);
|
||||
}
|
||||
Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle, new Object[]{});
|
||||
if (Equinox_BundleLoader_createClassLoader_method == null && bundleLoader != null)
|
||||
{
|
||||
Equinox_BundleLoader_createClassLoader_method =
|
||||
bundleLoader.getClass().getClassLoader().loadClass(bundleLoaderName).getDeclaredMethod("createClassLoader", new Class[]{});
|
||||
Equinox_BundleLoader_createClassLoader_method.setAccessible(true);
|
||||
}
|
||||
return (ClassLoader)Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader, new Object[]{});
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.warn("Unable to get equinox bundle classloader", t);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (osgiContainer == OSGiContainerType.EquinoxLuna)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Equinox_EquinoxBundle_getModuleClassLoader_Method == null)
|
||||
Equinox_EquinoxBundle_getModuleClassLoader_Method = Equinox_EquinoxBundle_Class.getDeclaredMethod("getModuleClassLoader", new Class[]{
|
||||
Boolean.TYPE
|
||||
});
|
||||
|
||||
Equinox_EquinoxBundle_getModuleClassLoader_Method.setAccessible(true);
|
||||
return (ClassLoader)Equinox_EquinoxBundle_getModuleClassLoader_Method.invoke(bundle, new Object[]{
|
||||
Boolean.FALSE
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to get equinox luna bundle classloader", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
LOG.warn("No classloader for equinox platform for bundle {}", bundle.getSymbolicName());
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static ClassLoader internalGetFelixBundleClassLoader(Bundle bundle)
|
||||
{
|
||||
|
||||
if (osgiContainer == OSGiContainerType.Felix403)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Felix_BundleWiring_Class == null)
|
||||
Felix_BundleWiring_Class = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
|
||||
|
||||
Felix_BundleImpl_Adapt_Method.setAccessible(true);
|
||||
|
||||
if (Felix_BundleWiring_getClassLoader_Method == null)
|
||||
{
|
||||
Felix_BundleWiring_getClassLoader_Method = Felix_BundleWiring_Class.getDeclaredMethod("getClassLoader");
|
||||
Felix_BundleWiring_getClassLoader_Method.setAccessible(true);
|
||||
}
|
||||
|
||||
Object wiring = Felix_BundleImpl_Adapt_Method.invoke(bundle, new Object[]{Felix_BundleWiring_Class});
|
||||
return (ClassLoader)Felix_BundleWiring_getClassLoader_Method.invoke(wiring);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to get felix bundle classloader", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (osgiContainer == OSGiContainerType.FelixOld)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Felix_BundleImpl_m_Modules_Field == null)
|
||||
{
|
||||
Felix_BundleImpl_m_Modules_Field = Felix_BundleImpl_Class.getDeclaredField("m_modules");
|
||||
Felix_BundleImpl_m_Modules_Field.setAccessible(true);
|
||||
}
|
||||
|
||||
// Figure out which version of the modules is exported
|
||||
Object currentModuleImpl;
|
||||
|
||||
try
|
||||
{
|
||||
Object[] moduleArray = (Object[])Felix_BundleImpl_m_Modules_Field.get(bundle);
|
||||
currentModuleImpl = moduleArray[moduleArray.length - 1];
|
||||
}
|
||||
catch (Throwable ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<Object> moduleArray = (List<Object>)Felix_BundleImpl_m_Modules_Field.get(bundle);
|
||||
currentModuleImpl = moduleArray.get(moduleArray.size() - 1);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to get field {}", Felix_BundleImpl_m_Modules_Field, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Felix_ModuleImpl_m_ClassLoader_Field == null && currentModuleImpl != null)
|
||||
{
|
||||
String felixFrameworkModuleImplClassName = "org.apache.felix.framework.ModuleImpl";
|
||||
String felixFrameworkModuleImplClassLoaderField = "m_classLoader";
|
||||
try
|
||||
{
|
||||
Felix_ModuleImpl_m_ClassLoader_Field = bundle.getClass().getClassLoader().loadClass(felixFrameworkModuleImplClassName).getDeclaredField(felixFrameworkModuleImplClassLoaderField);
|
||||
Felix_ModuleImpl_m_ClassLoader_Field.setAccessible(true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to find field {}.{}", felixFrameworkModuleImplClassName, felixFrameworkModuleImplClassLoaderField, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// first make sure that the classloader is ready:
|
||||
// the m_classLoader field must be initialized by the
|
||||
// ModuleImpl.getClassLoader() private method.
|
||||
ClassLoader cl = null;
|
||||
try
|
||||
{
|
||||
cl = (ClassLoader)Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl);
|
||||
if (cl != null)
|
||||
return cl;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to get field {}", Felix_ModuleImpl_m_ClassLoader_Field, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
// looks like it was not ready:
|
||||
// the m_classLoader field must be initialized by the
|
||||
// ModuleImpl.getClassLoader() private method.
|
||||
// this call will do that.
|
||||
try
|
||||
{
|
||||
bundle.loadClass("java.lang.Object");
|
||||
cl = (ClassLoader)Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl);
|
||||
return cl;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to get field {}", Felix_ModuleImpl_m_ClassLoader_Field, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to load old felix container", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
LOG.warn("No classloader for felix platform for bundle {}", bundle.getSymbolicName());
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static ClassLoader internalGetConciergeBundleClassLoader(Bundle bundle)
|
||||
{
|
||||
if (osgiContainer == OSGiContainerType.Concierge)
|
||||
{
|
||||
try
|
||||
{
|
||||
/**
|
||||
* In Concierge:
|
||||
*
|
||||
* Option A:
|
||||
* <pre>
|
||||
* Concierge concierge = new Concierge(...);
|
||||
* BundleWiring bundleWiring = concierge.getWiring(); // method is public
|
||||
* </pre>
|
||||
* Problem: getWiring not yet implementd
|
||||
*
|
||||
* Option B:
|
||||
* <pre>
|
||||
* Concierge concierge = new Concierge(...);
|
||||
* BundleWiring bundleWiring = concierge.adapt(org.osgi.framework.wiring.BundleWiring);
|
||||
* </pre>
|
||||
* Same approach as done in Felix.
|
||||
*
|
||||
*/
|
||||
if (Concierge_BundleWiring_Class == null)
|
||||
{
|
||||
Concierge_BundleWiring_Class = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
|
||||
Concierge_BundleImpl_Adapt_Method = Concierge_BundleImpl_Class.getMethod("adapt", new Class[]{Class.class});
|
||||
Concierge_BundleImpl_Adapt_Method.setAccessible(true);
|
||||
Concierge_BundleWiring_getClassLoader_Method = Concierge_BundleWiring_Class.getMethod("getClassLoader");
|
||||
Concierge_BundleWiring_getClassLoader_Method.setAccessible(true);
|
||||
}
|
||||
|
||||
Object wiring = Concierge_BundleImpl_Adapt_Method.invoke(bundle, new Object[]{Concierge_BundleWiring_Class});
|
||||
ClassLoader cl = (ClassLoader)Concierge_BundleWiring_getClassLoader_Method.invoke(wiring);
|
||||
return cl;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to load Concierge platform", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
LOG.warn("No classloader for Concierge platform for bundle {}", bundle.getSymbolicName());
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,385 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee10.osgi.boot.utils.internal;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.eclipse.jetty.ee10.osgi.boot.utils.BundleFileLocatorHelper;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.PathResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
/**
|
||||
* DefaultFileLocatorHelper
|
||||
* <p>
|
||||
* From a bundle to its location on the filesystem. Assumes the bundle is not a
|
||||
* jar.
|
||||
*/
|
||||
public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
||||
{
|
||||
|
||||
// hack to locate the file-system directly from the bundle.
|
||||
// support equinox, felix and nuxeo's osgi implementations.
|
||||
// not tested on nuxeo and felix just yet.
|
||||
// The url nuxeo and felix return is created directly from the File so it
|
||||
// should work.
|
||||
private static Field BUNDLE_ENTRY_FIELD = null;
|
||||
|
||||
private static Field FILE_FIELD = null;
|
||||
|
||||
private static Field BUNDLE_FILE_FIELD_FOR_DIR_ZIP_BUNDLE_ENTRY = null; // ZipBundleFile
|
||||
|
||||
// inside
|
||||
// DirZipBundleEntry
|
||||
|
||||
private static Field ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE = null; // ZipFile
|
||||
|
||||
private static final String[] FILE_BUNDLE_ENTRY_CLASSES = {
|
||||
"org.eclipse.osgi.baseadaptor.bundlefile.FileBundleEntry", "org.eclipse.osgi.storage.bundlefile.FileBundleEntry"
|
||||
};
|
||||
private static final String[] ZIP_BUNDLE_ENTRY_CLASSES = {
|
||||
"org.eclipse.osgi.baseadaptor.bundlefile.ZipBundleEntry", "org.eclipse.osgi.storage.bundlefile.ZipBundleEntry"
|
||||
};
|
||||
private static final String[] DIR_ZIP_BUNDLE_ENTRY_CLASSES = {
|
||||
"org.eclipse.osgi.baseadaptor.bundlefile.DirZipBundleEntry", "org.eclipse.osgi.storage.bundlefile.DirZipBundleEntry"
|
||||
};
|
||||
private static final String[] BUNDLE_URL_CONNECTION_CLASSES = {
|
||||
"org.eclipse.osgi.framework.internal.core.BundleURLConnection", "org.eclipse.osgi.storage.url.BundleURLConnection"
|
||||
};
|
||||
|
||||
public static boolean match(String name, String... names)
|
||||
{
|
||||
if (name == null || names == null)
|
||||
return false;
|
||||
boolean matched = false;
|
||||
for (int i = 0; i < names.length && !matched; i++)
|
||||
{
|
||||
if (name.equals(names[i]))
|
||||
matched = true;
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
/**
|
||||
* Works with equinox, felix, nuxeo and probably more. Not exactly in the
|
||||
* spirit of OSGi but quite necessary to support self-contained webapps and
|
||||
* other situations.
|
||||
*
|
||||
* @param bundle The bundle
|
||||
* @return Its installation location as a file.
|
||||
* @throws Exception if unable to get the bundle install location
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public File getBundleInstallLocation(Bundle bundle) throws Exception
|
||||
{
|
||||
// String installedBundles = System.getProperty("osgi.bundles");
|
||||
// grab the MANIFEST.MF's url
|
||||
// and then do what it takes.
|
||||
URL url = bundle.getEntry("/META-INF/MANIFEST.MF");
|
||||
|
||||
if (url.getProtocol().equals("file"))
|
||||
{
|
||||
// some osgi frameworks do use the file protocol directly in some
|
||||
// situations. Do use the PathResource to transform the URL into a
|
||||
// File: URL#toURI is broken
|
||||
return new PathResource(url).getFile().getParentFile().getParentFile().getCanonicalFile();
|
||||
}
|
||||
else if (url.getProtocol().equals("bundleentry"))
|
||||
{
|
||||
// say hello to equinox who has its own protocol.
|
||||
// we use introspection like there is no tomorrow to get access to
|
||||
// the File
|
||||
|
||||
URLConnection con = url.openConnection();
|
||||
con.setUseCaches(Resource.getDefaultUseCaches()); // work around
|
||||
// problems where
|
||||
// url connections
|
||||
// cache
|
||||
// references to
|
||||
// jars
|
||||
|
||||
if (BUNDLE_ENTRY_FIELD == null)
|
||||
{
|
||||
BUNDLE_ENTRY_FIELD = con.getClass().getDeclaredField("bundleEntry");
|
||||
BUNDLE_ENTRY_FIELD.setAccessible(true);
|
||||
}
|
||||
Object bundleEntry = BUNDLE_ENTRY_FIELD.get(con);
|
||||
|
||||
if (match(bundleEntry.getClass().getName(), FILE_BUNDLE_ENTRY_CLASSES))
|
||||
{
|
||||
if (FILE_FIELD == null)
|
||||
{
|
||||
FILE_FIELD = bundleEntry.getClass().getDeclaredField("file");
|
||||
FILE_FIELD.setAccessible(true);
|
||||
}
|
||||
File f = (File)FILE_FIELD.get(bundleEntry);
|
||||
return f.getParentFile().getParentFile().getCanonicalFile();
|
||||
}
|
||||
else if (match(bundleEntry.getClass().getName(), ZIP_BUNDLE_ENTRY_CLASSES))
|
||||
{
|
||||
url = bundle.getEntry("/");
|
||||
|
||||
con = url.openConnection();
|
||||
con.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
|
||||
if (BUNDLE_ENTRY_FIELD == null)
|
||||
{
|
||||
// this one will be a DirZipBundleEntry
|
||||
BUNDLE_ENTRY_FIELD = con.getClass().getDeclaredField("bundleEntry");
|
||||
BUNDLE_ENTRY_FIELD.setAccessible(true);
|
||||
}
|
||||
bundleEntry = BUNDLE_ENTRY_FIELD.get(con);
|
||||
if (BUNDLE_FILE_FIELD_FOR_DIR_ZIP_BUNDLE_ENTRY == null)
|
||||
{
|
||||
BUNDLE_FILE_FIELD_FOR_DIR_ZIP_BUNDLE_ENTRY = bundleEntry.getClass().getDeclaredField("bundleFile");
|
||||
BUNDLE_FILE_FIELD_FOR_DIR_ZIP_BUNDLE_ENTRY.setAccessible(true);
|
||||
}
|
||||
Object zipBundleFile = BUNDLE_FILE_FIELD_FOR_DIR_ZIP_BUNDLE_ENTRY.get(bundleEntry);
|
||||
if (ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE == null)
|
||||
{
|
||||
ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE = zipBundleFile.getClass().getDeclaredField("zipFile");
|
||||
ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE.setAccessible(true);
|
||||
}
|
||||
ZipFile zipFile = (ZipFile)ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE.get(zipBundleFile);
|
||||
return new File(zipFile.getName());
|
||||
}
|
||||
else if (match(bundleEntry.getClass().getName(), DIR_ZIP_BUNDLE_ENTRY_CLASSES))
|
||||
{
|
||||
// that will not happen as we did ask for the manifest not a
|
||||
// directory.
|
||||
}
|
||||
}
|
||||
else if ("bundle".equals(url.getProtocol()))
|
||||
{
|
||||
// observed this on felix-2.0.0
|
||||
String location = bundle.getLocation();
|
||||
if (location.startsWith("file:/"))
|
||||
{
|
||||
URI uri = new URI(URIUtil.encodePath(location));
|
||||
return new File(uri).getCanonicalFile();
|
||||
}
|
||||
else if (location.startsWith("file:"))
|
||||
{
|
||||
// location defined in the BundleArchive m_bundleArchive
|
||||
// it is relative to relative to the BundleArchive's
|
||||
// m_archiveRootDir
|
||||
File res = new File(location.substring("file:".length()));
|
||||
if (!res.exists())
|
||||
{
|
||||
return null;
|
||||
// Object bundleArchive = getFelixBundleArchive(bundle);
|
||||
// File archiveRoot =
|
||||
// getFelixBundleArchiveRootDir(bundleArchive);
|
||||
// String currentLocation =
|
||||
// getFelixBundleArchiveCurrentLocation(bundleArchive);
|
||||
// System.err.println("Got the archive root " +
|
||||
// archiveRoot.getAbsolutePath()
|
||||
// + " current location " + currentLocation +
|
||||
// " is directory ?");
|
||||
// res = new File(archiveRoot, currentLocation != null
|
||||
// ? currentLocation : location.substring("file:".length()));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
else if (location.startsWith("reference:file:"))
|
||||
{
|
||||
location = URLDecoder.decode(location.substring("reference:".length()), "UTF-8");
|
||||
File file = new File(location.substring("file:".length())).getCanonicalFile();
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate a file inside a bundle.
|
||||
*
|
||||
* @param bundle the bundle
|
||||
* @param path the path
|
||||
* @return file object
|
||||
* @throws Exception if unable to get the file in the bundle
|
||||
*/
|
||||
@Override
|
||||
public File getFileInBundle(Bundle bundle, String path) throws Exception
|
||||
{
|
||||
if (path != null && path.length() > 0 && path.charAt(0) == '/')
|
||||
{
|
||||
path = path.substring(1);
|
||||
}
|
||||
File bundleInstall = getBundleInstallLocation(bundle);
|
||||
File webapp = path != null && path.length() != 0 ? new File(bundleInstall, path) : bundleInstall;
|
||||
if (!webapp.exists())
|
||||
{
|
||||
throw new IllegalArgumentException("Unable to locate " + path + " inside " + bundle.getSymbolicName() +
|
||||
" (" + (bundleInstall != null ? bundleInstall.getAbsolutePath() : " no_bundle_location ") + ")");
|
||||
}
|
||||
return webapp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method equivalent to Bundle#getEntry(String entryPath) except that
|
||||
* it searches for entries in the fragments by using the Bundle#findEntries
|
||||
* method.
|
||||
*
|
||||
* @param bundle the bundle
|
||||
* @param entryPath the entry path
|
||||
* @return null or all the entries found for that path.
|
||||
*/
|
||||
@Override
|
||||
public Enumeration<URL> findEntries(Bundle bundle, String entryPath)
|
||||
{
|
||||
int last = entryPath.lastIndexOf('/');
|
||||
String path = last != -1 && last < entryPath.length() - 2 ? entryPath.substring(0, last) : "/";
|
||||
if (!path.startsWith("/"))
|
||||
{
|
||||
path = "/" + path;
|
||||
}
|
||||
String pattern = last != -1 && last < entryPath.length() - 2 ? entryPath.substring(last + 1) : entryPath;
|
||||
@SuppressWarnings("unchecked")
|
||||
Enumeration<URL> enUrls = bundle.findEntries(path, pattern, false);
|
||||
return enUrls;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the bundle is a jar, returns the jar. If the bundle is a folder, look
|
||||
* inside it and search for jars that it returns.
|
||||
* <p>
|
||||
* Good enough for our purpose (TldLocationsCache when it scans for tld
|
||||
* files inside jars alone. In fact we only support the second situation for
|
||||
* development purpose where the bundle was imported in pde and the classes
|
||||
* kept in a jar.
|
||||
* </p>
|
||||
*
|
||||
* @param bundle the bundle
|
||||
* @return The jar(s) file that is either the bundle itself, either the jars
|
||||
* embedded inside it.
|
||||
*/
|
||||
@Override
|
||||
public File[] locateJarsInsideBundle(Bundle bundle) throws Exception
|
||||
{
|
||||
File jasperLocation = getBundleInstallLocation(bundle);
|
||||
if (jasperLocation.isDirectory())
|
||||
{
|
||||
// try to find the jar files inside this folder
|
||||
ArrayList<File> urls = new ArrayList<>();
|
||||
for (File f : jasperLocation.listFiles())
|
||||
{
|
||||
if (FileID.isJavaArchive(f.getName()) && f.isFile())
|
||||
{
|
||||
urls.add(f);
|
||||
}
|
||||
else if (f.isDirectory() && f.getName().equals("lib"))
|
||||
{
|
||||
for (File f2 : jasperLocation.listFiles())
|
||||
{
|
||||
if (FileID.isJavaArchive(f2.getName()) && f2.isFile())
|
||||
{
|
||||
urls.add(f2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return urls.toArray(new File[urls.size()]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new File[]{jasperLocation};
|
||||
}
|
||||
}
|
||||
|
||||
// introspection on equinox to invoke the getLocalURL method on
|
||||
// BundleURLConnection
|
||||
// equivalent to using the FileLocator without depending on an equinox
|
||||
// class.
|
||||
private static Method BUNDLE_URL_CONNECTION_getLocalURL = null;
|
||||
|
||||
private static Method BUNDLE_URL_CONNECTION_getFileURL = null;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@Override
|
||||
public URL getLocalURL(URL url)
|
||||
throws Exception
|
||||
{
|
||||
if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol()))
|
||||
{
|
||||
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
if (BUNDLE_URL_CONNECTION_getLocalURL == null && match(conn.getClass().getName(), BUNDLE_URL_CONNECTION_CLASSES))
|
||||
{
|
||||
BUNDLE_URL_CONNECTION_getLocalURL = conn.getClass().getMethod("getLocalURL");
|
||||
BUNDLE_URL_CONNECTION_getLocalURL.setAccessible(true);
|
||||
}
|
||||
if (BUNDLE_URL_CONNECTION_getLocalURL != null)
|
||||
{
|
||||
return (URL)BUNDLE_URL_CONNECTION_getLocalURL.invoke(conn);
|
||||
}
|
||||
}
|
||||
return 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.
|
||||
* </p>
|
||||
*
|
||||
* @return a URL to the content of the bundle entry that uses the file:
|
||||
* protocol
|
||||
* @throws Exception if unable to get the file url
|
||||
*/
|
||||
@Override
|
||||
public URL getFileURL(URL url) throws Exception
|
||||
|
||||
{
|
||||
if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol()))
|
||||
{
|
||||
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
if (BUNDLE_URL_CONNECTION_getFileURL == null && match(conn.getClass().getName(), BUNDLE_URL_CONNECTION_CLASSES))
|
||||
{
|
||||
BUNDLE_URL_CONNECTION_getFileURL = conn.getClass().getMethod("getFileURL");
|
||||
BUNDLE_URL_CONNECTION_getFileURL.setAccessible(true);
|
||||
}
|
||||
if (BUNDLE_URL_CONNECTION_getFileURL != null)
|
||||
{
|
||||
return (URL)BUNDLE_URL_CONNECTION_getFileURL.invoke(conn);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
org.eclipse.jetty.ee10.osgi.annotations.AnnotationConfiguration
|
||||
org.eclipse.jetty.ee10.osgi.boot.OSGiWebInfConfiguration
|
||||
org.eclipse.jetty.ee10.osgi.boot.OSGiMetaInfConfiguration
|
||||
|
|
|
@ -12,23 +12,30 @@
|
|||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<osgi-version>3.17.200</osgi-version>
|
||||
<osgi-services-version>3.10.200</osgi-services-version>
|
||||
<osgi-util-version>3.6.100</osgi-util-version>
|
||||
<osgi-version>3.18.100</osgi-version>
|
||||
<osgi-annotation-version>8.1.0</osgi-annotation-version>
|
||||
<osgi-services-version>3.11.0</osgi-services-version>
|
||||
<osgi-service-cm-version>1.6.1</osgi-service-cm-version>
|
||||
<osgi-service-component-version>1.5.0</osgi-service-component-version>
|
||||
<osgi-service-event-version>1.4.1</osgi-service-event-version>
|
||||
<osgi-util-version>3.7.100</osgi-util-version>
|
||||
<osgi-util-function-version>1.2.0</osgi-util-function-version>
|
||||
<osgi-util-promise-version>1.2.0</osgi-util-promise-version>
|
||||
<osgi-util-measurement-version>1.0.2</osgi-util-measurement-version>
|
||||
<osgi-util-position-version>1.0.1</osgi-util-position-version>
|
||||
<osgi-util-tracker-version>1.5.4</osgi-util-tracker-version>
|
||||
<osgi-util-xml-version>1.0.2</osgi-util-xml-version>
|
||||
<equinox-http-servlet-version>1.0.0-v20070606</equinox-http-servlet-version>
|
||||
<jacoco.skip>true</jacoco.skip>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>jetty-ee10-osgi-alpn</module>
|
||||
<module>jetty-ee10-osgi-boot</module>
|
||||
<module>jetty-ee10-osgi-boot-jsp</module>
|
||||
<module>jetty-ee10-osgi-boot-warurl</module>
|
||||
<module>test-jetty-ee10-osgi-webapp</module>
|
||||
<module>test-jetty-ee10-osgi-webapp-resources</module>
|
||||
<module>test-jetty-ee10-osgi-context</module>
|
||||
<module>test-jetty-ee10-osgi-fragment</module>
|
||||
<module>test-jetty-ee10-osgi-server</module>
|
||||
<module>jetty-ee10-osgi-alpn</module>
|
||||
<module>test-jetty-ee10-osgi</module>
|
||||
</modules>
|
||||
|
||||
|
@ -60,24 +67,6 @@
|
|||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<!-- necessary because x.y.x-SNAPSHOT is not a valid osgi version -->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>set-servlet-api-version</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>parse-version</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<versionString>${jetty.servlet.api.version}</versionString>
|
||||
<propertyPrefix>servletImpl</propertyPrefix>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-eclipse-plugin</artifactId>
|
||||
|
@ -117,11 +106,36 @@
|
|||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
<version>${osgi-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.service.cm</artifactId>
|
||||
<version>${osgi-service-cm-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.service.component</artifactId>
|
||||
<version>${osgi-service-component-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.service.event</artifactId>
|
||||
<version>${osgi-service-event-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.util.tracker</artifactId>
|
||||
<version>${osgi-util-tracker-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.equinox.http</groupId>
|
||||
<artifactId>servlet</artifactId>
|
||||
<version>${equinox-http-servlet-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>osgi.annotation</artifactId>
|
||||
<version>${osgi-annotation-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
<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.ee10.osgi</groupId>
|
||||
<artifactId>jetty-ee10-osgi-project</artifactId>
|
||||
<version>12.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>test-jetty-ee10-osgi-context</artifactId>
|
||||
<name>EE10 :: Jetty :: OSGi :: Test Context</name>
|
||||
<description>Test Jetty OSGi bundle with a ContextHandler</description>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.testcontext</bundle-symbolic-name>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
<maven.javadoc.skip>true</maven.javadoc.skip>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/context</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>org.eclipse.jetty.ee10.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 accommodate 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>
|
||||
jakarta.servlet;version="[$(version;==;${servletImpl.osgiVersion}),$(version;+;${servletImpl.osgiVersion}))",
|
||||
jakarta.servlet.resources;version="[$(version;==;${servletImpl.osgiVersion}),$(version;+;${servletImpl.osgiVersion}))",
|
||||
org.osgi.framework,
|
||||
org.osgi.service.cm;version="1.2.0",
|
||||
org.osgi.service.packageadmin,
|
||||
org.osgi.service.startlevel;version="1.0.0",
|
||||
org.osgi.service.url;version="1.0.0",
|
||||
org.osgi.util.tracker;version="1.3.0",
|
||||
*
|
||||
</Import-Package>
|
||||
<DynamicImport-Package>org.eclipse.jetty.*;version="[$(version;==;${parsedVersion.osgiVersion}),$(version;+;${parsedVersion.osgiVersion}))"</DynamicImport-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
|
||||
|
||||
<Set name="contextPath">/unset</Set>
|
||||
|
||||
<!-- Set up the base resource for static files relative to inside bundle -->
|
||||
<Set name="baseResourceAsString"><Property name="bundle.root"/>/static/</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>
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package com.acme.osgi;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import jakarta.servlet.ServletContextEvent;
|
||||
import jakarta.servlet.ServletContextListener;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
/**
|
||||
* Bootstrap a ContextHandler
|
||||
*/
|
||||
public class Activator implements BundleActivator
|
||||
{
|
||||
|
||||
private ServiceRegistration _sr;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void start(final BundleContext context) throws Exception
|
||||
{
|
||||
ContextHandler ch = new ContextHandler();
|
||||
ch.addEventListener(new ServletContextListener()
|
||||
{
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce)
|
||||
{
|
||||
//System.err.println("Context is initialized");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce)
|
||||
{
|
||||
//System.err.println("CONTEXT IS DESTROYED!");
|
||||
}
|
||||
});
|
||||
Dictionary props = new Hashtable();
|
||||
props.put("Web-ContextPath", "/acme");
|
||||
props.put("Jetty-ContextFilePath", "acme.xml");
|
||||
_sr = context.registerService(ContextHandler.class.getName(), ch, props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the activator.
|
||||
*
|
||||
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
|
||||
*/
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception
|
||||
{
|
||||
_sr.unregister();
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
<html>
|
||||
<body>
|
||||
<h1>Test OSGi Context</h1>
|
||||
<p>ContextHandler registered as a service successfully deployed.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -57,7 +57,7 @@
|
|||
org.xml.sax.helpers,
|
||||
*
|
||||
</Import-Package>
|
||||
<DynamicImport-Package>org.eclipse.jetty.*;version="[$(version;==;${parsedVersion.osgiVersion}),$(version;+;${parsedVersion.osgiVersion}))"</DynamicImport-Package>
|
||||
<DynamicImport-Package>org.eclipse.jetty.*;version="[$(version;==;${parsedVersion.osgiVersion}),$(version;+;${parsedVersion.osgiVersion}))", org.eclipse.jetty.ee10.*;version="[$(version;==;${parsedVersion.osgiVersion}),$(version;+;${parsedVersion.osgiVersion}))"</DynamicImport-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -47,7 +47,8 @@
|
|||
</supportedProjectTypes>
|
||||
<instructions>
|
||||
<Export-Package>!com.acme*</Export-Package>
|
||||
<Web-ContextPath>/</Web-ContextPath>
|
||||
<Web-ContextPath>/test-webapp-resources</Web-ContextPath>
|
||||
<Jetty-Environment>ee10</Jetty-Environment>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
<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.ee10.osgi</groupId>
|
||||
<artifactId>jetty-ee10-osgi-project</artifactId>
|
||||
<version>12.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>test-jetty-ee10-osgi-webapp</artifactId>
|
||||
<name>EE10 :: Jetty :: OSGi :: Test WebApp</name>
|
||||
<description>Test Jetty OSGi Webapp bundle</description>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.webapp</bundle-symbolic-name>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
<maven.javadoc.skip>true</maven.javadoc.skip>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10</groupId>
|
||||
<artifactId>jetty-ee10-webapp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.platform</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>org.eclipse.jetty.ee10.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 accommodate pretty much any versions
|
||||
of the packages it uses; no need to reflect some tight dependency determined at
|
||||
compilation time. -->
|
||||
<Export-Package>com.acme.osgi</Export-Package>
|
||||
<DynamicImport-Package>org.eclipse.jetty.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))"</DynamicImport-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -1,91 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package com.acme.osgi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Dictionary;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
|
||||
/**
|
||||
* Bootstrap a webapp
|
||||
*/
|
||||
public class Activator implements BundleActivator
|
||||
{
|
||||
|
||||
private ServiceRegistration _srA;
|
||||
private ServiceRegistration _srB;
|
||||
|
||||
public static class TestServlet extends HttpServlet
|
||||
{
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
//report the mimetype of a file
|
||||
String mimetype = req.getServletContext().getMimeType("file.gz");
|
||||
resp.setContentType("text/html");
|
||||
PrintWriter writer = resp.getWriter();
|
||||
writer.write("<html><body><p>MIMETYPE=" + mimetype + "</p></body</html>");
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void start(BundleContext context) throws Exception
|
||||
{
|
||||
//Create webappA as a Service and target it at the default server
|
||||
WebAppContext webapp = new WebAppContext();
|
||||
webapp.addServlet(new ServletHolder(new TestServlet()), "/mime");
|
||||
Dictionary props = new Hashtable();
|
||||
props.put("Jetty-WarResourcePath", "webappA");
|
||||
props.put("Web-ContextPath", "/acme");
|
||||
props.put("managedServerName", "defaultJettyServer");
|
||||
_srA = context.registerService(WebAppContext.class.getName(), webapp, props);
|
||||
|
||||
//Create a second webappB as a Service and target it at a custom Server
|
||||
//deployed by another bundle
|
||||
final WebAppContext webappB = new WebAppContext();
|
||||
Dictionary propsB = new Hashtable();
|
||||
propsB.put("Jetty-WarResourcePath", "webappB");
|
||||
propsB.put("Web-ContextPath", "/acme");
|
||||
propsB.put("managedServerName", "fooServer");
|
||||
_srB = context.registerService(WebAppContext.class.getName(), webappB, propsB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the activator.
|
||||
*
|
||||
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
|
||||
*/
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception
|
||||
{
|
||||
_srA.unregister();
|
||||
_srB.unregister();
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
<html>
|
||||
<body>
|
||||
<h1>Test OSGi WebApp</h1>
|
||||
<p>Webapp registered by bundle as service successfully deployed.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +0,0 @@
|
|||
<html>
|
||||
<body>
|
||||
<h1>Test OSGi WebAppA</h1>
|
||||
<p>Webapp registered by bundle as service successfully deployed.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +0,0 @@
|
|||
<html>
|
||||
<body>
|
||||
<h1>Test OSGi WebAppB</h1>
|
||||
<p>Webapp registered by bundle as service successfully deployed.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -17,9 +17,8 @@
|
|||
<pax.url.version>2.6.2</pax.url.version>
|
||||
<swissbox.version>1.8.3</swissbox.version>
|
||||
<tinybundles.version>3.0.0</tinybundles.version>
|
||||
<spifly.version>1.3.4</spifly.version>
|
||||
<!-- TODO -->
|
||||
<skipTests>true</skipTests>
|
||||
<spifly.version>1.3.6</spifly.version>
|
||||
<injection.bundle.version>1.2</injection.bundle.version>
|
||||
<maven.javadoc.skip>true</maven.javadoc.skip>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
@ -138,17 +137,43 @@
|
|||
<version>1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.util.promise</artifactId>
|
||||
<version>${osgi-util-promise-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.util.measurement</artifactId>
|
||||
<version>${osgi-util-measurement-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.util.position</artifactId>
|
||||
<version>${osgi-util-position-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.util.xml</artifactId>
|
||||
<version>${osgi-util-xml-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Jetty OSGi Deps -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-slf4j-impl</artifactId>
|
||||
|
@ -255,6 +280,11 @@
|
|||
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
|
||||
</dependency>
|
||||
<!-- Jetty Deps -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10</groupId>
|
||||
<artifactId>jetty-ee10-jndi</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10</groupId>
|
||||
<artifactId>jetty-ee10-annotations</artifactId>
|
||||
|
@ -306,32 +336,32 @@
|
|||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10</groupId>
|
||||
<groupId>org.eclipse.jetty.ee10.websocket</groupId>
|
||||
<artifactId>jetty-ee10-websocket-jetty-api</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10</groupId>
|
||||
<groupId>org.eclipse.jetty.ee10.websocket</groupId>
|
||||
<artifactId>jetty-ee10-websocket-jetty-common</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10</groupId>
|
||||
<groupId>org.eclipse.jetty.ee10.websocket</groupId>
|
||||
<artifactId>jetty-ee10-websocket-jetty-client</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10</groupId>
|
||||
<groupId>org.eclipse.jetty.ee10.websocket</groupId>
|
||||
<artifactId>jetty-ee10-websocket-jakarta-client</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10</groupId>
|
||||
<groupId>org.eclipse.jetty.ee10.websocket</groupId>
|
||||
<artifactId>jetty-ee10-websocket-servlet</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10</groupId>
|
||||
<groupId>org.eclipse.jetty.ee10.websocket</groupId>
|
||||
<artifactId>jetty-ee10-websocket-jetty-server</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
@ -341,7 +371,7 @@
|
|||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10</groupId>
|
||||
<groupId>org.eclipse.jetty.ee10.websocket</groupId>
|
||||
<artifactId>jetty-ee10-websocket-jakarta-server</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
@ -353,12 +383,6 @@
|
|||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>jetty-http2-hpack</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10.osgi</groupId>
|
||||
<artifactId>jetty-ee10-osgi-alpn</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-alpn-server</artifactId>
|
||||
|
@ -370,32 +394,38 @@
|
|||
<artifactId>jetty-ee10-plus</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10.osgi</groupId>
|
||||
<artifactId>jetty-ee10-osgi-alpn</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Eclipse OSGi Deps -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10.demos</groupId>
|
||||
<artifactId>demo-jsp-webapp</artifactId>
|
||||
<artifactId>jetty-ee10-demo-jsp-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>webbundle</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10.demos</groupId>
|
||||
<artifactId>demo-jetty-webapp</artifactId>
|
||||
<artifactId>jetty-ee10-demo-jetty-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>webbundle</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10.demos</groupId>
|
||||
<artifactId>demo-spec-webapp</artifactId>
|
||||
<artifactId>jetty-ee10-demo-spec-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10.demos</groupId>
|
||||
<artifactId>demo-container-initializer</artifactId>
|
||||
<artifactId>jetty-ee10-demo-container-initializer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
@ -420,21 +450,9 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10.demos</groupId>
|
||||
<artifactId>demo-mock-resources</artifactId>
|
||||
<artifactId>jetty-ee10-demo-mock-resources</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10.osgi</groupId>
|
||||
<artifactId>test-jetty-ee10-osgi-context</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.ee10.osgi</groupId>
|
||||
<artifactId>test-jetty-ee10-osgi-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
|
@ -525,6 +543,12 @@
|
|||
<settingsFilePath>${env.GLOBAL_MVN_SETTINGS}</settingsFilePath>
|
||||
</systemPropertyVariables>
|
||||
<argLine>-Dconscrypt-version=${conscrypt.version}</argLine>
|
||||
<!-- TODO -->
|
||||
<excludes>
|
||||
<exclude>**/TestJettyOSGiBootHTTP2Conscrypt.java</exclude>
|
||||
<exclude>**/TestJettyOSGiBootHTTP2JDK9.java</exclude>
|
||||
<exclude>**/TestJettyOSGiBootWithJakartaWebSocket.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
<!-- paxexam still using junit 4 so we have to force the provider here -->
|
||||
<dependencies>
|
||||
|
|
|
@ -12,10 +12,6 @@
|
|||
<Set name="contexts">
|
||||
<Ref refid="Contexts" />
|
||||
</Set>
|
||||
<Call name="setContextAttribute">
|
||||
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
|
||||
<Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg>
|
||||
</Call>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<!-- ============================================================= -->
|
||||
<!-- Configure the Jetty Server instance with an ID "Server" -->
|
||||
<!-- by adding an HTTP connector. -->
|
||||
<!-- This configuration must be used in conjunction with jetty.xml -->
|
||||
<!-- ============================================================= -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add an HTTP Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with a single -->
|
||||
<!-- HttpConnectionFactory instance using the common httpConfig -->
|
||||
<!-- instance defined in jetty.xml -->
|
||||
<!-- -->
|
||||
<!-- Consult the javadoc of o.e.j.server.ServerConnector and -->
|
||||
<!-- o.e.j.server.HttpConnectionFactory for all configuration -->
|
||||
<!-- that may be set here. -->
|
||||
<!-- =========================================================== -->
|
||||
<Call name="addConnector">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.server.ServerConnector">
|
||||
<Arg name="server"><Ref refid="Server" /></Arg>
|
||||
<Arg name="factories">
|
||||
<Array type="org.eclipse.jetty.server.ConnectionFactory">
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
|
||||
<Arg name="config"><Ref refid="httpConfig" /></Arg>
|
||||
</New>
|
||||
</Item>
|
||||
</Array>
|
||||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.osgi.boot.utils.ServerConnectorListener">
|
||||
<Set name="sysPropertyName">boot.context.service.port</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
<Set name="host" property="jetty.http.host"/>
|
||||
<Set name="port"><Property name="jetty.http.port" default="80"/></Set>
|
||||
<Set name="idleTimeout"><Property name="jetty.http.idleTimeout" default="30000"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
</Configure>
|
|
@ -1,48 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<!-- ============================================================= -->
|
||||
<!-- Configure the Jetty Server instance with an ID "Server" -->
|
||||
<!-- by adding an HTTP connector. -->
|
||||
<!-- This configuration must be used in conjunction with jetty.xml -->
|
||||
<!-- ============================================================= -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add an HTTP Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with a single -->
|
||||
<!-- HttpConnectionFactory instance using the common httpConfig -->
|
||||
<!-- instance defined in jetty.xml -->
|
||||
<!-- -->
|
||||
<!-- Consult the javadoc of o.e.j.server.ServerConnector and -->
|
||||
<!-- o.e.j.server.HttpConnectionFactory for all configuration -->
|
||||
<!-- that may be set here. -->
|
||||
<!-- =========================================================== -->
|
||||
<Call name="addConnector">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.server.ServerConnector">
|
||||
<Arg name="server"><Ref refid="Server" /></Arg>
|
||||
<Arg name="factories">
|
||||
<Array type="org.eclipse.jetty.server.ConnectionFactory">
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
|
||||
<Arg name="config"><Ref refid="httpConfig" /></Arg>
|
||||
</New>
|
||||
</Item>
|
||||
</Array>
|
||||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.osgi.boot.utils.ServerConnectorListener">
|
||||
<Set name="sysPropertyName">boot.webapp.service.port</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
<Set name="host" property="jetty.http.host"/>
|
||||
<Set name="port"><Property name="jetty.http.port" default="80"/></Set>
|
||||
<Set name="idleTimeout"><Property name="jetty.http.idleTimeout" default="30000"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
</Configure>
|
|
@ -33,7 +33,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.osgi.boot.utils.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.osgi.util.ServerConnectorListener">
|
||||
<Set name="sysPropertyName">boot.annotations.port</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.osgi.boot.utils.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.osgi.util.ServerConnectorListener">
|
||||
<Set name="sysPropertyName">boot.bundle.port</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.osgi.boot.utils.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.osgi.util.ServerConnectorListener">
|
||||
<Set name="sysPropertyName">boot.jakarta.websocket.port</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.osgi.boot.utils.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.osgi.util.ServerConnectorListener">
|
||||
<Set name="sysPropertyName">boot.jsp.port</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.osgi.boot.utils.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.osgi.util.ServerConnectorListener">
|
||||
<Set name="sysPropertyName">boot.resources.port</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.osgi.boot.utils.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.osgi.util.ServerConnectorListener">
|
||||
<Set name="sysPropertyName">boot.websocket.port</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue